Annotation of ntddk/src/mmedia/mmdrv/wavedd.c, revision 1.1.1.1

1.1       root        1: /****************************************************************************
                      2:  *
                      3:  *   wavedd.c
                      4:  *
                      5:  *   Multimedia kernel driver support component (mmdrv)
                      6:  *
                      7:  *   Copyright (c) 1991 Microsoft Corporation.  All Rights Reserved.
                      8:  *
                      9:  *   Driver for wave input and output devices
                     10:  *
                     11:  *   -- Wave driver entry points (wodMessage, widMessage)
                     12:  *   -- Auxiliary task (necessary for receiving Apcs and generating
                     13:  *      callbacks ASYNCRHONOUSLY)
                     14:  *   -- Interface to kernel driver (via DeviceIoControl)
                     15:  *
                     16:  *   Note that if any error occurs then the kernel device is closed
                     17:  *   and all subsequent calls requiring calls to the kernel device
                     18:  *   return error until the device is closed by the application.
                     19:  *
                     20:  *   History
                     21:  *      01-Feb-1992 - Robin Speed (RobinSp) wrote it
                     22:  *      04-Feb-1992 - SteveDav reviewed it
                     23:  *      08-Feb-1992 - RobinSp - Redesign to chop up caller's data.
                     24:  *                          Also does loops so we can remove them from the
                     25:  *                          kernel driver.
                     26:  *
                     27:  ***************************************************************************/
                     28: 
                     29: #include "mmdrv.h"
                     30: #include <ntddwave.h>
                     31: 
                     32: /*****************************************************************************
                     33: 
                     34:     internal declarations
                     35: 
                     36:  ****************************************************************************/
                     37: 
                     38: #define D1 dprintf1
                     39: #define D2 dprintf2
                     40: #define D3 dprintf3
                     41: 
                     42: // Stack size for our auxiliary task
                     43: 
                     44: #define WAVE_STACK_SIZE 300
                     45: 
                     46: typedef enum {
                     47:     WaveThreadInvalid,
                     48:     WaveThreadAddBuffer,
                     49:     WaveThreadSetState,
                     50:     WaveThreadSetData,
                     51:     WaveThreadGetData,
                     52:     WaveThreadBreakLoop,
                     53:     WaveThreadClose,
                     54:     WaveThreadTerminate
                     55: } WAVETHREADFUNCTION;
                     56: 
                     57: 
                     58: #define MAX_BUFFER_SIZE           8192  // Largest buffer we send to device
                     59: #define MAX_WAVE_BYTES          5*8192  // Max bytes we have queued on was 22000
                     60: 
                     61: //
                     62: // Structure to hide our overlapped structure in so we can get some
                     63: // context on IO completion
                     64: //
                     65: 
                     66: typedef struct {
                     67:     OVERLAPPED Ovl;
                     68:     LPWAVEHDR WaveHdr;
                     69: } WAVEOVL, *PWAVEOVL;
                     70: 
                     71: // per allocation structure for wave
                     72: typedef struct tag_WAVEALLOC {
                     73:     struct tag_WAVEALLOC *Next;         // Chaining
                     74:     UINT                DeviceNumber;   // Which device
                     75:     UINT                DeviceType;     // WaveInput or WaveOutput
                     76:     DWORD               dwCallback;     // client's callback
                     77:     DWORD               dwInstance;     // client's instance data
                     78:     DWORD               dwFlags;        // Open flags
                     79:     HWAVE               hWave;          // handle for stream
                     80: 
                     81:     HANDLE              hDev;           // Wave device handle
                     82:     LPWAVEHDR           DeviceQueue;    // Buffers queued by application
                     83:     LPWAVEHDR           NextBuffer;     // Next buffer to send to device
                     84:     DWORD               BufferPosition; // How far we're into a large buffer
                     85:     DWORD               BytesOutstanding;
                     86:                                         // Bytes being processed by device
                     87:     LPWAVEHDR           LoopHead;       // Start of loop if any
                     88:     DWORD               LoopCount;      // Number more loops to go
                     89: 
                     90:     WAVEOVL             DummyWaveOvl;   // For break loop
                     91:                                                                                 //
                     92:     HANDLE              Event;          // Event for driver syncrhonization
                     93:                                         // and notification of auxiliary
                     94:                                         // task operation completion.
                     95:     WAVETHREADFUNCTION  AuxFunction;    // Function for thread to perform
                     96:     union {
                     97:         LPWAVEHDR       pHdr;           // Buffer to pass in aux task
                     98:         ULONG           State;          // State to set
                     99:         struct {
                    100:             ULONG       Function;       // IOCTL to use
                    101:             PBYTE       pData;          // Data to set or get
                    102:             ULONG       DataLen;        // Length of data
                    103:         } GetSetData;
                    104: 
                    105:     } AuxParam;
                    106:                                         // 0 means terminate task.
                    107:     HANDLE              AuxEvent1;      // Aux thread waits on this
                    108:     HANDLE              AuxEvent2;      // Caller of Aux thread waits on this
                    109:     HANDLE              ThreadHandle;   // Handle for thread termination ONLY
                    110:     MMRESULT            AuxReturnCode;  // Return code from Aux task
                    111: }WAVEALLOC, *PWAVEALLOC;
                    112: 
                    113: PWAVEALLOC WaveHandleList;              // Our chain of wave handles
                    114: 
                    115: 
                    116: //
                    117: // extra flag to track buffer completion
                    118: //
                    119: 
                    120: #define WHDR_COMPLETE 0x80000000
                    121: 
                    122: /*****************************************************************************
                    123: 
                    124:     internal function prototypes
                    125: 
                    126:  ****************************************************************************/
                    127: 
                    128: STATIC MMRESULT waveGetDevCaps(DWORD id, UINT DeviceType, LPBYTE lpCaps,
                    129:                             DWORD dwSize);
                    130: STATIC DWORD    waveThread(LPVOID lpParameter);
                    131: STATIC void     waveCleanUp(PWAVEALLOC pClient);
                    132: STATIC MMRESULT waveThreadCall(WAVETHREADFUNCTION Function, PWAVEALLOC pClient);
                    133: STATIC MMRESULT waveSetState(PWAVEALLOC pClient, ULONG State);
                    134: STATIC MMRESULT waveWrite(LPWAVEHDR pHdr, PWAVEALLOC pClient);
                    135: STATIC void     waveBlockFinished(LPWAVEHDR lpHdr, DWORD MsgId);
                    136: STATIC void     waveCallback(PWAVEALLOC pWave, DWORD msg, DWORD dw1);
                    137: STATIC void     waveCompleteBuffers(PWAVEALLOC pClient);
                    138: STATIC void     waveFreeQ(PWAVEALLOC pClient);
                    139: STATIC void     waveOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
                    140: 
                    141: /* Attempt to pre-touch up to MIN(iSize,PRETOUCHLIMIT) bytes on from pb.
                    142:    If AllowFault then keep going to fault the stuff in.
                    143:    Otherwise stop as soon as you notice the clock ticking
                    144: */
                    145: //PreTouch(BYTE * pb, int iSize, BOOL AllowFault)
                    146: //{
                    147: //    DWORD dwTicks = GetTickCount();
                    148: //    int pages = 0;
                    149: //    static int Headway[100];
                    150: //    static int c = 0;
                    151: //    static int TotalTouches = 0;
                    152: //    static int TimesThrough = 0;   // number of times this code has run.
                    153: //
                    154: //    if (iSize > PRETOUCHLIMIT) {
                    155: //        iSize = PRETOUCHLIMIT;
                    156: //    }
                    157: //
                    158: //    ++TimesThrough;
                    159: //
                    160: //    // pre-touch the pages but get out if it's taking too long
                    161: //    // (which probably means we took a page fault.
                    162: //    // Touch at least 2 pages as we may want 2 pages per DMA 1/2 buffer.
                    163: //    while (iSize>0) {
                    164: //        volatile BYTE b;
                    165: //        b = *pb;
                    166: //        pb += 4096;    // move to next page.  Are they ALWAYS 4096?
                    167: //        iSize -= 4096; // and count it off
                    168: //        ++pages;
                    169: //        ++TotalTouches;
                    170: //        if (dwTicks<GetTickCount() && pages>1 && !AllowFault) break;
                    171: //    }
                    172: //    Headway[c] = pages;
                    173: //    ++c;
                    174: //
                    175: //    if (c==100){
                    176: //        for (c=0; c<=99; c += 10){
                    177: //            dprintf(("%5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld",Headway[c],Headway[c+1],Headway[c+2],Headway[c+3],Headway[c+4],Headway[c+5],Headway[c+6],Headway[c+7],Headway[c+8],Headway[c+9]));
                    178: //        }
                    179: //        dprintf((" "));
                    180: //        c = 0;
                    181: //    }
                    182: //}
                    183: 
                    184: 
                    185: /****************************************************************************
                    186:  * @doc INTERNAL
                    187:  *
                    188:  * @api VOID | TerminateWave | Free all wave resources
                    189:  *
                    190:  * @rdesc None
                    191:  ***************************************************************************/
                    192: VOID TerminateWave(VOID)
                    193: {
                    194: #ifdef TERMINATE
                    195: 
                    196:     //
                    197:     // This is all wrong - we need to find out how to terminate threads !
                    198:     //
                    199: 
                    200:     PWAVEALLOC pClient;
                    201: 
                    202:     //
                    203:     // Remove all our threads and their resources
                    204:     //
                    205: 
                    206:     for (pClient = WaveHandleList; pClient != NULL; pClient = pClient->Next) {
                    207:         if (pClient->ThreadHandle) {
                    208:             //
                    209:             // Kill our thread.  But be careful !  It may
                    210:             // already have gone away - so don't wait for
                    211:             // it to set its event, just wait for it
                    212:             // to finish
                    213:             //
                    214: 
                    215:             //
                    216:             // Set the function code
                    217:             //
                    218:             pClient->AuxFunction = WaveThreadTerminate;
                    219: 
                    220:             //
                    221:             // Kick off the thread
                    222:             //
                    223:             SetEvent(pClient->AuxEvent1);
                    224: 
                    225:             //
                    226:             // We created our threads with mmTaskCreate so it's
                    227:             // safe to wait on them
                    228:             //
                    229:             WaitForSingleObject(pClient->ThreadHandle, INFINITE);
                    230:         }
                    231:         waveCleanUp(pClient);
                    232:     }
                    233: #endif
                    234: }
                    235: 
                    236: /****************************************************************************
                    237:  * @doc INTERNAL
                    238:  *
                    239:  * @api void | waveGetDevCaps | Get the device capabilities.
                    240:  *
                    241:  * @parm DWORD | id | Device id
                    242:  *
                    243:  * @parm UINT | DeviceType | type of device
                    244:  *
                    245:  * @parm LPBYTE | lpCaps | Far pointer to a WAVEOUTCAPS structure to
                    246:  *      receive the information.
                    247:  *
                    248:  * @parm DWORD | dwSize | Size of the WAVEOUTCAPS structure.
                    249:  *
                    250:  * @rdesc MMSYS.. return code.
                    251:  ***************************************************************************/
                    252: STATIC MMRESULT waveGetDevCaps(DWORD id, UINT DeviceType,
                    253:                             LPBYTE lpCaps, DWORD dwSize)
                    254: {
                    255:     return sndGetData(DeviceType, id, dwSize, lpCaps,
                    256:                       IOCTL_WAVE_GET_CAPABILITIES);
                    257: }
                    258: 
                    259: /****************************************************************************
                    260:  * @doc INTERNAL
                    261:  *
                    262:  * @api DWORD | waveGetPos | Get the stream position in samples.
                    263:  *
                    264:  * @parm PWAVEALLOC | pClient | Client handle.
                    265:  *
                    266:  * @parm LPMMTIME | lpmmt | Far pointer to an MMTIME structure.
                    267:  *
                    268:  * @parm DWORD | dwSize | Size of the MMTIME structure.
                    269:  *
                    270:  * @rdesc MMSYS... return value.
                    271:  ***************************************************************************/
                    272: MMRESULT waveGetPos(PWAVEALLOC pClient, LPMMTIME lpmmt, DWORD dwSize)
                    273: {
                    274:     WAVE_DD_POSITION PositionData;
                    275:     MMRESULT mErr;
                    276: 
                    277:     if (dwSize < sizeof(MMTIME))
                    278:         return MMSYSERR_ERROR;
                    279: 
                    280:     //
                    281:     // Get the current position from the driver
                    282:     //
                    283:     mErr = sndGetHandleData(pClient->hDev,
                    284:                             sizeof(PositionData),
                    285:                             &PositionData,
                    286:                             IOCTL_WAVE_GET_POSITION,
                    287:                             pClient->Event);
                    288: 
                    289:     if (mErr == MMSYSERR_NOERROR) {
                    290:         if (lpmmt->wType == TIME_BYTES) {
                    291:             lpmmt->u.cb = PositionData.ByteCount;
                    292:         }
                    293: 
                    294:         // default is samples.
                    295:         else {
                    296:             lpmmt->wType = TIME_SAMPLES;
                    297:             lpmmt->u.sample = PositionData.SampleCount;
                    298:         }
                    299:     }
                    300: 
                    301:     return mErr;
                    302: }
                    303: 
                    304: /****************************************************************************
                    305:  * @doc INTERNAL
                    306:  *
                    307:  * @api MMRESULT | waveOpen | Open wave device and set up logical device data
                    308:  *    and auxilary task for issuing requests and servicing Apc's
                    309:  *
                    310:  * @parm WAVEDEVTYPE | DeviceType | Whether it's a wave input or output device
                    311:  *
                    312:  * @parm DWORD | id | The device logical id
                    313:  *
                    314:  * @parm DWORD | msg | Input parameter to wodMessage
                    315:  *
                    316:  * @parm DWORD | dwUser | Input parameter to wodMessage - pointer to
                    317:  *   application's handle (generated by this routine)
                    318:  *
                    319:  * @parm DWORD | dwParam1 | Input parameter to wodMessage
                    320:  *
                    321:  * @parm DWORD | dwParam2 | Input parameter to wodMessage
                    322:  *
                    323:  * @rdesc wodMessage return code.
                    324:  ***************************************************************************/
                    325: 
                    326: STATIC MMRESULT waveOpen(UINT  DeviceType,
                    327:                          DWORD id,
                    328:                          DWORD dwUser,
                    329:                          DWORD dwParam1,
                    330:                          DWORD dwParam2)
                    331: {
                    332:     PWAVEALLOC     pClient;  // pointer to client information structure
                    333:     MMRESULT mRet;
                    334:     BOOL Result;
                    335:     DWORD BytesReturned;
                    336:         LPPCMWAVEFORMAT Format;
                    337: 
                    338:     // dwParam1 contains a pointer to a WAVEOPENDESC
                    339:     // dwParam2 contains wave driver specific flags in the LOWORD
                    340:     // and generic driver flags in the HIWORD
                    341: 
                    342:     //
                    343:     // If it's only a query to check if the device supports our format
                    344:     // we :
                    345:     //     Open the device
                    346:     //     Test the format
                    347:     //     Close the device
                    348:     //
                    349: 
                    350:     if (dwParam2 & WAVE_FORMAT_QUERY) {
                    351:         HANDLE hDev;
                    352: 
                    353:         //
                    354:         // See if we can open our device
                    355:         // Only open for read (this should always work for our devices
                    356:         // unless there are system problems).
                    357:         //
                    358: 
                    359:         mRet = sndOpenDev(DeviceType,
                    360:                            id,
                    361:                            &hDev,
                    362:                            GENERIC_READ);
                    363: 
                    364:         if (mRet != MMSYSERR_NOERROR) {
                    365:             return mRet;
                    366:         }
                    367: 
                    368:         //
                    369:         // Check the format
                    370:         //
                    371:                 Format = (LPPCMWAVEFORMAT)((LPWAVEOPENDESC)dwParam1)->lpFormat;
                    372:         Result = DeviceIoControl(
                    373:                         hDev,
                    374:                         IOCTL_WAVE_QUERY_FORMAT,
                    375:                         (PVOID)Format,
                    376:                         sizeof(PCMWAVEFORMAT) +
                    377:                                                 (Format->wf.wFormatTag == WAVE_FORMAT_PCM ? 0 :
                    378:                                                                        *(LPWORD)(Format + 1)),
                    379:                                                      // Input buffer size
                    380:                         NULL,                        // Output buffer
                    381:                         0,                           // Output buffer size
                    382:                         &BytesReturned,
                    383:                         NULL);
                    384: 
                    385: 
                    386:         //
                    387:         // Only a query so close the device
                    388:         //
                    389: 
                    390:         CloseHandle(hDev);
                    391: 
                    392:         return Result ? MMSYSERR_NOERROR :
                    393:                GetLastError() == ERROR_NOT_SUPPORTED ? WAVERR_BADFORMAT :
                    394:                                                 sndTranslateStatus();
                    395:     }
                    396: 
                    397:     //
                    398:     // See if we've got this device already in our list (in
                    399:     // which case we have a thread and events for it already made)
                    400:     //
                    401: 
                    402:     EnterCriticalSection(&mmDrvCritSec);
                    403: 
                    404:     for (pClient = WaveHandleList;
                    405:          pClient != NULL;
                    406:          pClient = pClient->Next) {
                    407:         if (pClient->DeviceNumber == id &&
                    408:             pClient->DeviceType == DeviceType) {
                    409:             //
                    410:             // We already have a thread and resources for this device
                    411:             //
                    412: 
                    413:             if (pClient->hDev != INVALID_HANDLE_VALUE) {
                    414:                 //
                    415:                 // Someone else is using it!
                    416:                 //
                    417: 
                    418:                 LeaveCriticalSection(&mmDrvCritSec);
                    419:                 return MMSYSERR_ALLOCATED;
                    420:             }
                    421:             break;
                    422:         }
                    423:     }
                    424: 
                    425:     //
                    426:     // allocate my per-client structure and zero it (LPTR).
                    427:     //
                    428: 
                    429:     if (pClient == NULL) {
                    430:         pClient = (PWAVEALLOC)HeapAlloc(hHeap, 0, sizeof(WAVEALLOC));
                    431:         if (pClient == NULL) {
                    432:             LeaveCriticalSection(&mmDrvCritSec);
                    433:             return MMSYSERR_NOMEM;
                    434:         }
                    435: 
                    436:         dprintf2(("Creating new device resource for device id %d, type %s",
                    437:                  id,
                    438:                  DeviceType == WaveInDevice ? "Wave Input" : "Wave Output"));
                    439: 
                    440:         memset((PVOID)pClient, 0, sizeof(WAVEALLOC));
                    441: 
                    442:         //
                    443:         // Add it to the list
                    444:         //
                    445:         pClient->DeviceNumber = id;
                    446:         pClient->DeviceType = DeviceType;
                    447:         pClient->Next = WaveHandleList;
                    448:         WaveHandleList = pClient;
                    449:     }
                    450: 
                    451: 
                    452:     //
                    453:     // and fill it with info
                    454:     //
                    455: 
                    456:     pClient->dwCallback  = ((LPWAVEOPENDESC)dwParam1)->dwCallback;
                    457:     pClient->dwInstance  = ((LPWAVEOPENDESC)dwParam1)->dwInstance;
                    458:     pClient->hWave       = ((LPWAVEOPENDESC)dwParam1)->hWave;
                    459:     pClient->dwFlags     = dwParam2;
                    460: 
                    461:     // pClient->hDev is initialized by sndOpenDev
                    462: 
                    463:     pClient->DeviceQueue = NULL;
                    464:     pClient->NextBuffer  = NULL;
                    465:     pClient->BufferPosition = 0;
                    466:     pClient->BytesOutstanding = 0;
                    467:     pClient->LoopHead    = NULL;
                    468:     pClient->LoopCount   = 0;
                    469: 
                    470:     //
                    471:     // See if we can open our device
                    472:     // We could get ERROR_BUSY if someone else is has the device open
                    473:     // for writing.
                    474:     //
                    475: 
                    476:     mRet = sndOpenDev(DeviceType,
                    477:                        id,
                    478:                        &pClient->hDev,
                    479:                        (GENERIC_READ | GENERIC_WRITE));
                    480: 
                    481:     if (mRet != MMSYSERR_NOERROR) {
                    482: 
                    483:                 WinAssert(pClient->hDev == INVALID_HANDLE_VALUE);
                    484:         LeaveCriticalSection(&mmDrvCritSec);
                    485:         return mRet;
                    486:     }
                    487: 
                    488: 
                    489:     //
                    490:     // make sure we can handle the format and set it.
                    491:     //
                    492: 
                    493:     Result = DeviceIoControl(
                    494:                  pClient->hDev,
                    495:                  IOCTL_WAVE_SET_FORMAT,
                    496:                         (PVOID)((LPWAVEOPENDESC)dwParam1)->lpFormat,
                    497: /* BUGBUG NOT GENERAL */sizeof(PCMWAVEFORMAT),       // Input buffer size
                    498:                         NULL,                        // Output buffer
                    499:                         0,                           // Output buffer size
                    500:                         &BytesReturned,
                    501:                         NULL);
                    502: 
                    503: 
                    504:     if (!Result) {
                    505:         CloseHandle(pClient->hDev);
                    506:         pClient->hDev = INVALID_HANDLE_VALUE;
                    507:         LeaveCriticalSection(&mmDrvCritSec);
                    508:         return GetLastError() == ERROR_NOT_SUPPORTED ? WAVERR_BADFORMAT :
                    509:                                                 sndTranslateStatus();
                    510:     }
                    511: 
                    512:     LeaveCriticalSection(&mmDrvCritSec);
                    513: 
                    514:     //
                    515:     // Create our event for synchronization with the kernel driver
                    516:     //
                    517: 
                    518:     if (!pClient->Event) {
                    519:         pClient->Event = CreateEvent(NULL, FALSE, FALSE, NULL);
                    520:         if (pClient->Event == NULL) {
                    521:             waveCleanUp(pClient);
                    522:             return MMSYSERR_NOMEM;
                    523:         }
                    524:         //
                    525:         // Create our event for our thread to wait on
                    526:         //
                    527: 
                    528:         pClient->AuxEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
                    529:         if (!pClient->AuxEvent1) {
                    530:             waveCleanUp(pClient);
                    531:             return MMSYSERR_NOMEM;
                    532:         }
                    533:         //
                    534:         // Create our event for waiting for the auxiliary thread
                    535:         //
                    536: 
                    537:         pClient->AuxEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
                    538:         if (!pClient->AuxEvent2) {
                    539:             waveCleanUp(pClient);
                    540:             return MMSYSERR_NOMEM;
                    541:         }
                    542: 
                    543:         //
                    544:         // Create our auxiliary thread for sending buffers to the driver
                    545:         // and collecting Apcs
                    546:         //
                    547: 
                    548:         mRet = mmTaskCreate((LPTASKCALLBACK)waveThread,
                    549:                             &pClient->ThreadHandle,
                    550:                             (DWORD)pClient);
                    551: 
                    552:         if (mRet != MMSYSERR_NOERROR) {
                    553:             waveCleanUp(pClient);
                    554:             return MMSYSERR_NOMEM;
                    555:         }
                    556: 
                    557:         //
                    558:         // Make sure the thread has really started
                    559:         //
                    560: 
                    561:         WaitForSingleObject(pClient->AuxEvent2, INFINITE);
                    562:     }
                    563: 
                    564:     //
                    565:     // give the client my driver dw
                    566:     //
                    567:     {
                    568:         PWAVEALLOC *pUserHandle;
                    569:         pUserHandle = (PWAVEALLOC *)dwUser;
                    570:         *pUserHandle = pClient;
                    571:     }
                    572: 
                    573:     //
                    574:     // sent client his OPEN callback message
                    575:     //
                    576:     waveCallback(pClient, DeviceType == WaveOutDevice ? WOM_OPEN : WIM_OPEN, 0L);
                    577: 
                    578:     return MMSYSERR_NOERROR;
                    579: }
                    580: 
                    581: /****************************************************************************
                    582:  * @doc INTERNAL
                    583:  *
                    584:  * @api void | waveCleanUp | Free resources for a wave device
                    585:  *
                    586:  * @parm PWAVEALLOC | pClient | Pointer to a WAVEALLOC structure describing
                    587:  *      resources to be freed.
                    588:  *
                    589:  * @rdesc There is no return value.
                    590:  *
                    591:  * @comm If the pointer to the resource is NULL then the resource has not
                    592:  *     been allocated.
                    593:  ***************************************************************************/
                    594: STATIC void waveCleanUp(PWAVEALLOC pClient)
                    595: {
                    596:     EnterCriticalSection(&mmDrvCritSec);
                    597:     if (pClient->hDev != INVALID_HANDLE_VALUE) {
                    598:         CloseHandle(pClient->hDev);
                    599:         pClient->hDev = INVALID_HANDLE_VALUE;
                    600:     }
                    601:     if (pClient->AuxEvent1) {
                    602:         CloseHandle(pClient->AuxEvent1);
                    603:         pClient->AuxEvent1 = NULL;
                    604:     }
                    605:     if (pClient->AuxEvent2) {
                    606:         CloseHandle(pClient->AuxEvent2);
                    607:         pClient->AuxEvent2 = NULL;
                    608:     }
                    609:     if (pClient->Event) {
                    610:         CloseHandle(pClient->Event);
                    611:         pClient->Event = NULL;
                    612:     }
                    613:     LeaveCriticalSection(&mmDrvCritSec);
                    614: }
                    615: 
                    616: 
                    617: /****************************************************************************
                    618:  * @doc INTERNAL
                    619:  *
                    620:  * @api MMRESULT | waveWrite | Pass a new buffer to the Auxiliary thread for
                    621:  *       a wave device.
                    622:  *
                    623:  * @parm LPWAVEHDR | pHdr | Pointer to a wave buffer
                    624:  *
                    625:  * @parm PWAVEALLOC | pClient | The data associated with the logical wave
                    626:  *     device.
                    627:  *
                    628:  * @rdesc A MMSYS... type return code for the application.
                    629:  *
                    630:  * @comm The buffer flags are set and the buffer is passed to the auxiliary
                    631:  *     device task for processing.
                    632:  ***************************************************************************/
                    633: STATIC MMRESULT waveWrite(LPWAVEHDR pHdr, PWAVEALLOC pClient)
                    634: {
                    635:     //
                    636:     // Put the request at the end of our queue.
                    637:     //
                    638:     pHdr->dwFlags |= WHDR_INQUEUE;
                    639:     pHdr->dwFlags &= ~WHDR_DONE;
                    640:     pClient->AuxParam.pHdr = pHdr;
                    641:     return waveThreadCall(WaveThreadAddBuffer, pClient);
                    642: }
                    643: 
                    644: /****************************************************************************
                    645:  * @doc INTERNAL
                    646:  *
                    647:  * @api MMRESULT | waveSetState | Set a wave device to a given state
                    648:  *     This function is executed on the Auxiliary thread to synchronize
                    649:  *     correctly.
                    650:  *
                    651:  * @parm PWAVEALLOC | pClient | The data associated with the logical wave
                    652:  *     output device.
                    653:  *
                    654:  * @parm ULONG | State | The new state
                    655:  *
                    656:  * @rdesc A MMSYS... type return code for the application.
                    657:  ***************************************************************************/
                    658: STATIC MMRESULT waveSetState(PWAVEALLOC pClient, ULONG State)
                    659: {
                    660:     return sndSetHandleData(pClient->hDev,
                    661:                             sizeof(State),
                    662:                             &State,
                    663:                             IOCTL_WAVE_SET_STATE,
                    664:                             pClient->Event);
                    665: }
                    666: 
                    667: /****************************************************************************
                    668:  * @doc INTERNAL
                    669:  *
                    670:  * @api void | waveBlockFinished | This function sets the done bit and invokes
                    671:  *     the callback function if there is one.
                    672:  *
                    673:  * @parm LPWAVEHDR | lpHdr | Far pointer to the header.
                    674:  *
                    675:  * @rdesc There is no return value.
                    676:  ***************************************************************************/
                    677: STATIC void waveBlockFinished(LPWAVEHDR lpHdr, DWORD MsgId)
                    678: {
                    679:     PWAVEALLOC pWav;
                    680: 
                    681:     D3(("blkfin: lpHdr = %x", lpHdr));
                    682:     // Clear our private flag
                    683:     lpHdr->dwFlags &= ~WHDR_COMPLETE;
                    684: 
                    685:     // We are giving the block back to the application.  The header is no
                    686:     // longer in our queue, so we reset the WHDR_INQUEUE bit.  Also, we
                    687:     // clear our driver specific bit and cauterize the lpNext pointer.
                    688:     lpHdr->dwFlags &= ~WHDR_INQUEUE;
                    689:     lpHdr->lpNext = NULL;
                    690: 
                    691:     pWav = (PWAVEALLOC)(lpHdr->reserved);
                    692: 
                    693:     // set the 'done' bit - note that some people poll this bit.
                    694:     lpHdr->dwFlags |= WHDR_DONE;
                    695: 
                    696:     // invoke the callback function
                    697:     waveCallback(pWav, MsgId, (DWORD)lpHdr);
                    698: }
                    699: 
                    700: 
                    701: /****************************************************************************
                    702:  * @doc INTERNAL
                    703:  *
                    704:  * @api MMRESULT | waveThreadCall | Set the function for the thread to perform
                    705:  *     and 'call' the thread using the event pair mechanism.
                    706:  *
                    707:  * @parm WAVETHREADFUNCTION | Function | The function to perform
                    708:  *
                    709:  * @parm PWAVEALLOC | Our logical device data
                    710:  *
                    711:  * @rdesc An MMSYS... type return value suitable for returning to the
                    712:  *      application
                    713:  *
                    714:  * @comm The AuxParam field in the device data is the 'input' to
                    715:  *      the function processing loop in WaveThread().
                    716:  ***************************************************************************/
                    717: STATIC MMRESULT waveThreadCall(WAVETHREADFUNCTION Function, PWAVEALLOC pClient)
                    718: {
                    719:     //
                    720:     // Trap any failures
                    721:     //
                    722:     WinAssert(pClient->hDev != INVALID_HANDLE_VALUE);
                    723: 
                    724:     //
                    725:     // Set the function code
                    726:     //
                    727:     pClient->AuxFunction = Function;
                    728: 
                    729:     //
                    730:     // Kick off the thread
                    731:     //
                    732:     SetEvent(pClient->AuxEvent1);
                    733: 
                    734:     //
                    735:     // Wait for it to complete
                    736:     //
                    737:     WaitForSingleObject(pClient->AuxEvent2, INFINITE);
                    738: 
                    739:     //
                    740:     // Return the return code that our task set.
                    741:     //
                    742:     return pClient->AuxReturnCode;
                    743: }
                    744: 
                    745: /****************************************************************************
                    746:  * @doc INTERNAL
                    747:  *
                    748:  * @api MMRESULT | wavePartialApc | Called when a partial buffer is complete.
                    749:  *
                    750:  * @parm DWORD | BytesTransferred | Not relevant to us
                    751:  *
                    752:  * @parm LPOVERLAPPED | pOverLapped | Overlapped structure for this callback
                    753:  *
                    754:  * @rdesc None
                    755:  *
                    756:  * @comm The IO status block is freed and the BytesOutstanding count
                    757:  *       used to limit the buffers we have locked down is updated (we
                    758:  *       know here that parital buffers are all the same size).
                    759:  *       Also the byte count for a recording buffer is updated.
                    760:  ***************************************************************************/
                    761: STATIC void wavePartialOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
                    762: {
                    763:     LPWAVEHDR pHdr;
                    764:     PWAVEALLOC pClient;
                    765: 
                    766:     pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;
                    767:     D3(("wavePartialOvl: pHdr = %x", pHdr));
                    768: 
                    769:     pClient = (PWAVEALLOC)pHdr->reserved;
                    770: 
                    771:     //
                    772:     // We can't trust the IO system to return our buffers in the right
                    773:     // order so we set a flag in the buffer but only complete buffers
                    774:     // at the FRONT of the queue which have the flag set.  In fact
                    775:     // we don't process the stuff here - leave that for when we
                    776:     // exit the wait because calling the client's callback can
                    777:     // do nasty things inside and Apc routine
                    778:     //
                    779: 
                    780:     WinAssert(pHdr->dwFlags & WHDR_INQUEUE);
                    781:     WinAssert(!(pHdr->dwFlags & WHDR_COMPLETE));
                    782: 
                    783:     //
                    784:     // Recalculate how many bytes are outstanding on the device
                    785:     //
                    786: 
                    787:     pClient->BytesOutstanding -= MAX_BUFFER_SIZE;
                    788: 
                    789:     //
                    790:     // Work out how much was recorded if we're a recording device
                    791:     //
                    792: 
                    793:     if (pClient->DeviceType == WaveInDevice) {
                    794:         pHdr->dwBytesRecorded += BytesTransferred;
                    795:     }
                    796: 
                    797:     //
                    798:     // Free our Iosb
                    799:     //
                    800: 
                    801:     HeapFree(hHeap, 0, (LPSTR)pOverlapped);
                    802: 
                    803: }
                    804: 
                    805: 
                    806: 
                    807: /****************************************************************************
                    808:  * @doc INTERNAL
                    809:  *
                    810:  * @api void | waveOvl | Called when a (user) buffer is complete.
                    811:  *
                    812:  * @parm DWORD | BytesTransferred | Not relevant to us
                    813:  *
                    814:  * @parm LPOVERLAPPED | pOverLapped | Overlapped structure for this callback
                    815:  *
                    816:  * @parm PIO_STATUS_BLOCK | The Io status block we used
                    817:  *
                    818:  * @rdesc None
                    819:  *
                    820:  * @comm The IO status block is freed and the BytesOutstanding count
                    821:  *       used to limit the buffers we have locked down is updated (we
                    822:  *       know here that parital buffers are all the same size so we
                    823:  *       can compute the size of the 'last' buffer for a given user buffer).
                    824:  *       Also the byte count for a recording buffer is updated.
                    825:  *       The user buffer is marked as 'DONE'.
                    826:  ***************************************************************************/
                    827: STATIC void waveOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
                    828: {
                    829:     PWAVEHDR pHdr;
                    830:     PWAVEALLOC pClient;
                    831: 
                    832:     pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;
                    833:     D3(("waveOvl: pHdr = %x", pHdr));
                    834:     pClient = (PWAVEALLOC)pHdr->reserved;
                    835: 
                    836:     //
                    837:     // We can't trust the IO system to return our buffers in the right
                    838:     // order so we set a flag in the buffer but only complete buffers
                    839:     // at the FRONT of the queue which have the flag set.  In fact
                    840:     // we don't process the stuff here - leave that for when we
                    841:     // exit the wait because calling the client's callback can
                    842:     // do nasty things inside and Apc routine
                    843:     //
                    844: 
                    845:     WinAssert(pHdr->dwFlags & WHDR_INQUEUE);
                    846:     WinAssert(!(pHdr->dwFlags & WHDR_COMPLETE));
                    847: 
                    848:     //
                    849:     // Mark buffer as done unless we're doing more loops with it
                    850:     //
                    851:     pHdr->dwFlags |= WHDR_COMPLETE;
                    852: 
                    853:     //
                    854:     // It's now our duty to see if there were some old loops lying
                    855:     // around earlier in the queue which are vestiges of old loops.
                    856:     //
                    857: 
                    858:     if (pHdr->dwFlags & WHDR_BEGINLOOP) {
                    859:         PWAVEHDR pHdrSearch;
                    860:         for (pHdrSearch = pClient->DeviceQueue ;
                    861:              pHdrSearch != pHdr ;
                    862:              pHdrSearch = pHdrSearch->lpNext) {
                    863:             WinAssert(pHdrSearch != NULL);
                    864:             pHdrSearch->dwFlags |= WHDR_COMPLETE;
                    865:         }
                    866:     }
                    867:     //
                    868:     // Recalculate how many bytes are outstanding on the device
                    869:     //
                    870: 
                    871:     if (pHdr->dwBufferLength) {
                    872:         pClient->BytesOutstanding -= (pHdr->dwBufferLength - 1) %
                    873:                                          MAX_BUFFER_SIZE + 1;
                    874:     }
                    875: 
                    876:     //
                    877:     // Work out how much was recorded if we're a recording device
                    878:     //
                    879: 
                    880:     if (pClient->DeviceType == WaveInDevice) {
                    881:         pHdr->dwBytesRecorded += BytesTransferred;
                    882:     }
                    883: 
                    884:     //
                    885:     // Free our Iosb
                    886:     //
                    887: 
                    888:     HeapFree(hHeap, 0, (LPSTR)pOverlapped);
                    889: 
                    890: }
                    891: 
                    892: /****************************************************************************
                    893:  * @doc INTERNAL
                    894:  *
                    895:  * @api MMRESULT | waveLoopOvl | Called when a (user) buffer is complete.
                    896:  *                               but the buffer was need for more loops.
                    897:  *
                    898:  * @parm DWORD | BytesTransferred | Not relevant to us
                    899:  *
                    900:  * @parm LPOVERLAPPED | pOverLapped | Overlapped structure for this callback
                    901:  *
                    902:  * @rdesc None
                    903:  *
                    904:  * @comm Same as waveApc but the buffer is not marked complete.
                    905:  ***************************************************************************/
                    906: STATIC void waveLoopOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
                    907: {
                    908:     DWORD dwFlags;
                    909:     PWAVEHDR pHdr;
                    910: 
                    911:     D3(("waveLoopOvl"));
                    912:     pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;
                    913: 
                    914:     //
                    915:     // Do it this way to avoid falling into a hole if the Apcs are
                    916:     // in the wrong order !!!
                    917:     //
                    918:     dwFlags = pHdr->dwFlags;
                    919:     waveOvl(dwErrorCode, BytesTransferred, pOverlapped);
                    920:     pHdr->dwFlags = dwFlags;
                    921: }
                    922: 
                    923: /****************************************************************************
                    924:  * @doc INTERNAL
                    925:  *
                    926:  * @api MMRESULT | waveBreakOvl | Used to chase out a buffer to break a loop.
                    927:  *
                    928:  * @parm DWORD | BytesTransferred | Not relevant to us
                    929:  *
                    930:  * @parm LPOVERLAPPED | pOverLapped | Overlapped structure for this callback
                    931:  *
                    932:  * @rdesc None
                    933:  *
                    934:  * @comm Mark the relevant buffer complete
                    935:  ***************************************************************************/
                    936: STATIC void waveBreakOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
                    937: {
                    938:     D3(("waveBreakOvl"));
                    939:     ((PWAVEOVL)pOverlapped)->WaveHdr->dwFlags |= WHDR_COMPLETE;
                    940: }
                    941: 
                    942: 
                    943: /****************************************************************************
                    944:  * @doc INTERNAL
                    945:  *
                    946:  * @api void | waveStart | Send more buffers to the device if possible
                    947:  *
                    948:  * @parm PWAVEALLOC | pClient | The client's handle data
                    949:  *
                    950:  * @rdesc There is no return code.
                    951:  *
                    952:  * @comm  The routine is called both when new buffers become available
                    953:  *        or when old buffers or parital buffers are completed so
                    954:  *        that device can accept more data.
                    955:  *
                    956:  *        No more that MAX_WAVE_BYTES in buffers no bigger than
                    957:  *        MAX_BUFFER_SIZE are to be outstanding on the device at
                    958:  *        any one time.
                    959:  *
                    960:  *        An additional complication is that we have to process loops
                    961:  *        which means (among other things) that the SAME BUFFER may
                    962:  *        appear multiple times in the driver's list (as different
                    963:  *        requests).  There are no loops for input devices.
                    964:  *        Loop buffers complete with Apcs which do not complete them
                    965:  *        (except for the final loop iteration) which means that if
                    966:  *        we decide unexpectedly to finish a loop (ie by waveOutBreakLoop)
                    967:  *        we must 'chase' the loop out with an artificial buffer to
                    968:  *        get our Apc going.
                    969:  *
                    970:  ***************************************************************************/
                    971: STATIC MMRESULT waveStart(PWAVEALLOC pClient)
                    972: {
                    973:     DWORD dwSize;
                    974:     BOOL Result;
                    975: 
                    976:     //
                    977:     // See if we can fit any more data on the device
                    978:     //
                    979: 
                    980:     WinAssert(pClient->hDev != INVALID_HANDLE_VALUE);
                    981: 
                    982:     while (pClient->NextBuffer) {
                    983:         PWAVEHDR pHdr;
                    984: 
                    985:         pHdr = pClient->NextBuffer;
                    986: 
                    987:         WinAssert(pClient->DeviceQueue != NULL);
                    988:                 WinAssert(!(pHdr->dwFlags & (WHDR_DONE | WHDR_COMPLETE)));
                    989: 
                    990:         dwSize = pHdr->dwBufferLength - pClient->BufferPosition;
                    991:         if (dwSize > MAX_BUFFER_SIZE) {
                    992:             dwSize = MAX_BUFFER_SIZE;
                    993:         }
                    994: 
                    995:         if (dwSize + pClient->BytesOutstanding <= MAX_WAVE_BYTES) {
                    996:             //
                    997:             // OK - we can fit another buffer in
                    998:             //
                    999:             // Don't have our overlay structure on the stack for an
                   1000:             // ASYNCHRONOUS IO !   Otherwise the IO subsystem will overwrite
                   1001:             // somebody else's data when the operation completes
                   1002:             //
                   1003:             PWAVEOVL pWaveOvl;
                   1004: 
                   1005:             if (pClient->BufferPosition == 0) {
                   1006:                 //
                   1007:                 // Start of new buffer
                   1008:                 // See if the buffer is the start of a new loop
                   1009:                 // (Check not continuation of old one)
                   1010:                 //
                   1011:                 if (pClient->NextBuffer &&
                   1012:                     (pClient->NextBuffer->dwFlags & WHDR_BEGINLOOP) &&
                   1013:                     pClient->NextBuffer != pClient->LoopHead) {
                   1014: 
                   1015:                     pClient->LoopHead = pClient->NextBuffer;
                   1016: 
                   1017:                     pClient->LoopCount = pClient->NextBuffer->dwLoops;
                   1018: 
                   1019:                     //
                   1020:                     // Loop count is number of times to play
                   1021:                     //
                   1022:                     if (pClient->LoopCount > 0) {
                   1023:                         pClient->LoopCount--;
                   1024:                     }
                   1025:                 }
                   1026:                 //
                   1027:                 // See if the loop is actually finished
                   1028:                 //
                   1029:                 if (pClient->LoopCount == 0) {
                   1030:                     pClient->LoopHead = NULL;
                   1031:                 }
                   1032: 
                   1033:             }
                   1034: 
                   1035:             pWaveOvl = (PWAVEOVL)HeapAlloc(hHeap, 0, sizeof(*pWaveOvl));
                   1036: 
                   1037:             if (pWaveOvl == NULL) {
                   1038:                 return MMSYSERR_NOMEM;
                   1039:             }
                   1040: 
                   1041:             memset((PVOID)pWaveOvl, 0, sizeof(*pWaveOvl));
                   1042: 
                   1043:             pWaveOvl->WaveHdr = pHdr;
                   1044: 
                   1045:             if (pClient->DeviceType == WaveOutDevice) {
                   1046:                 Result =  WriteFileEx(
                   1047:                               pClient->hDev,
                   1048:                                 (PBYTE)pHdr->lpData +        // Output buffer
                   1049:                                     pClient->BufferPosition,
                   1050:                               dwSize,
                   1051:                               (LPOVERLAPPED)pWaveOvl,      // Overlap structure
                   1052:                               pHdr->dwBufferLength !=
                   1053:                                   pClient->BufferPosition + dwSize ?
                   1054:                                   wavePartialOvl :
                   1055:                                   NULL != pClient->LoopHead ?
                   1056:                                       waveLoopOvl :
                   1057:                                       waveOvl);            // Overlap callback
                   1058:             } else {
                   1059:                 Result =  ReadFileEx(
                   1060:                               pClient->hDev,
                   1061:                                 (PBYTE)pHdr->lpData +        // Output buffer
                   1062:                                     pClient->BufferPosition,
                   1063:                               dwSize,
                   1064:                               (LPOVERLAPPED)pWaveOvl,      // Overlap structure
                   1065:                               pHdr->dwBufferLength !=
                   1066:                                   pClient->BufferPosition + dwSize ?
                   1067:                                   wavePartialOvl :
                   1068:                                   NULL != pClient->LoopHead ?
                   1069:                                       waveLoopOvl :
                   1070:                                       waveOvl);            // Overlap callback
                   1071:             }
                   1072: 
                   1073:             dprintf3(("Sent %u wave bytes to device, return code %8X",
                   1074:                      dwSize, GetLastError()));
                   1075: 
                   1076:             if (!Result && GetLastError() != ERROR_IO_PENDING) {
                   1077: 
                   1078:                         //
                   1079:                         // Free the Iosb since we won't be getting any callbacks
                   1080:                         //
                   1081:                         HeapFree(hHeap, 0, (LPSTR)pWaveOvl);
                   1082: 
                   1083:                 //
                   1084:                 // If the driver has not got any bytes outstanding then
                   1085:                 // everything may grind to a halt so release everything
                   1086:                 // here and notify 'completion' (ie mark all buffers
                   1087:                 // complete).  This is unsatisfactory but there's no
                   1088:                 // way of telling the application what happenend.
                   1089:                 //
                   1090: 
                   1091:                 if (pClient->BytesOutstanding == 0) {
                   1092: 
                   1093:                     //
                   1094:                     // This will cause acknowlegements to be made when
                   1095:                     // waveCompleteBuffers is run
                   1096:                     //
                   1097:                     waveFreeQ(pClient);
                   1098:                 }
                   1099:                 return sndTranslateStatus();
                   1100: 
                   1101:             } else {
                   1102:                 //
                   1103:                 // We successfully queued the buffer
                   1104:                 // Update our local data
                   1105:                 //
                   1106:                 pClient->BytesOutstanding += dwSize;
                   1107:                 pClient->BufferPosition += dwSize;
                   1108:                 if (pClient->BufferPosition == pHdr->dwBufferLength) {
                   1109:                     //
                   1110:                     // Finished this buffer - move on to the next
                   1111:                     //
                   1112:                     if (!pClient->LoopHead ||
                   1113:                         !(pHdr->dwFlags & WHDR_ENDLOOP)) {
                   1114:                         //
                   1115:                         // Not end of in a loop so we can free this buffer
                   1116:                         //
                   1117:                         pClient->NextBuffer = pHdr->lpNext;
                   1118: 
                   1119:                     } else {
                   1120:                         //
                   1121:                         // Finished a loop
                   1122:                         //
                   1123:                         if (pClient->LoopCount != 0) {
                   1124:                             pClient->LoopCount--;
                   1125:                             pClient->NextBuffer = pClient->LoopHead;
                   1126:                         } else {
                   1127:                             //
                   1128:                             // Someone's tried to kill us.  We have
                   1129:                             // to 'chase out' the start of this loop
                   1130:                             // so send a dummy (NULL) packet at the
                   1131:                             // back of the driver's queue
                   1132:                             //
                   1133: 
                   1134:                             pClient->DummyWaveOvl.WaveHdr = pClient->LoopHead;
                   1135: 
                   1136:                             Result =
                   1137:                                 WriteFileEx(
                   1138:                                     pClient->hDev,
                   1139:                                     (PVOID)pHdr->lpData,
                   1140:                                     0,
                   1141:                                     &pClient->DummyWaveOvl.Ovl, // Static for async
                   1142:                                     waveBreakOvl);
                   1143: 
                   1144:                             if (Result || GetLastError() == ERROR_IO_PENDING) {
                   1145:                                 pClient->LoopHead = NULL; // Loop complete
                   1146:                                 pClient->NextBuffer = pHdr->lpNext;
                   1147:                             }
                   1148:                         }
                   1149:                     }
                   1150:                     pClient->BufferPosition = 0;
                   1151:                 }
                   1152:             }
                   1153:             {
                   1154:             //    /* Before we go home, let's just touch ONE page - if there is one */
                   1155:             //    PBYTE pb = (PBYTE)pHdr->lpData + pClient->BufferPosition;
                   1156:             //    pb = ((DWORD)pb & 0xFFFFF000) + 0x1000;  /* find page start of next page */
                   1157:             //
                   1158:             //    if ( (PBYTE)pHdr->lpData + pHdr->dwBufferLength > pb )
                   1159:             //        PreTouch( pb, 1, FALSE);
                   1160: 
                   1161:             //    /* Before we go home, let's just try to pre-touch that which we will soon want */
                   1162:             //    PreTouch( (PBYTE)pHdr->lpData + pClient->BufferPosition
                   1163:             //            , pHdr->dwBufferLength - pClient->BufferPosition
                   1164:             //            , FALSE
                   1165:             //            );
                   1166:             }
                   1167: 
                   1168:         } else {
                   1169:             //
                   1170:             // Cannot fit any more bytes in at the moment
                   1171:             //
                   1172: 
                   1173: //            /* Before we go home, let's just try to pre-touch that which we will soon want */
                   1174: //            PreTouch( (PBYTE)pHdr->lpData + pClient->BufferPosition
                   1175: //                    , pHdr->dwBufferLength - pClient->BufferPosition
                   1176: //                    , FALSE
                   1177: //                    );
                   1178: 
                   1179:             /* NOW go home! */
                   1180:             break;
                   1181:         }
                   1182:     }
                   1183:     return MMSYSERR_NOERROR;
                   1184: }
                   1185: 
                   1186: 
                   1187: /****************************************************************************
                   1188:  * @doc INTERNAL
                   1189:  *
                   1190:  * @api void | waveCompleteBuffers | Buffer completion routine.  This completes
                   1191:  *     the work of the Apc routine at below Apc priority.  This gets
                   1192:  *     round the nasty situations arising when the user's callback
                   1193:  *     causes more apcs to run (I strongly suspect this is a kernel
                   1194:  *     bug).
                   1195:  *
                   1196:  * @parm PWAVEALLOC | pClient | The client's handle data
                   1197:  *
                   1198:  * @rdesc There is no return code.
                   1199:  ***************************************************************************/
                   1200: STATIC void waveCompleteBuffers(PWAVEALLOC pClient)
                   1201: {
                   1202:     //
                   1203:     // Process buffers from the front of our queue unless we're in
                   1204:     // a loop
                   1205:     //
                   1206: 
                   1207:     while (pClient->DeviceQueue &&
                   1208:            (pClient->DeviceQueue->dwFlags & WHDR_COMPLETE)) {
                   1209: 
                   1210:         PWAVEHDR pHdr;
                   1211: 
                   1212:         pHdr = pClient->DeviceQueue;
                   1213:         //
                   1214:         // Release buffer
                   1215:         //
                   1216:         pClient->DeviceQueue = pHdr->lpNext;
                   1217: 
                   1218: 
                   1219:         //
                   1220:         // Complete our buffer - note - this can cause another
                   1221:         // buffer to be marked as complete if the client's
                   1222:         // callback runs into an alertable wait.
                   1223:         //
                   1224: 
                   1225:         waveBlockFinished(pHdr,
                   1226:                           pClient->DeviceType == WaveOutDevice ?
                   1227:                           WOM_DONE : WIM_DATA);
                   1228:     }
                   1229: 
                   1230:     //
                   1231:     // We might be able to start some more output at this point
                   1232:     //
                   1233: 
                   1234:     waveStart(pClient);
                   1235: }
                   1236: 
                   1237: 
                   1238: /****************************************************************************
                   1239:  * @doc INTERNAL
                   1240:  *
                   1241:  * @api void | waveFreeQ | Mark all outstanding buffers complete
                   1242:  *
                   1243:  * @parm PWAVEALLOC | pClient | The client's handle data
                   1244:  *
                   1245:  * @rdesc There is no return code.
                   1246:  ***************************************************************************/
                   1247: STATIC void waveFreeQ(PWAVEALLOC pClient)
                   1248: {
                   1249:     PWAVEHDR pHdr;
                   1250:     for (pHdr = pClient->DeviceQueue;
                   1251:          pHdr != NULL;
                   1252:          pHdr = pHdr->lpNext) {
                   1253:         pHdr->dwFlags |= WHDR_COMPLETE;
                   1254:     }
                   1255:         //
                   1256:         // Tidy up next buffer
                   1257:         //
                   1258:         pClient->NextBuffer = NULL;
                   1259:         pClient->BufferPosition = 0;
                   1260: }
                   1261: 
                   1262: #if 0
                   1263: typedef struct {
                   1264:         LPBYTE Addr;
                   1265:         DWORD  Len;
                   1266: } PRETOUCHTHREADPARM;
                   1267: 
                   1268: /* asynchronous pre-toucher thread */
                   1269: DWORD PreToucher(DWORD dw)
                   1270: {
                   1271:     PRETOUCHTHREADPARM * pttp;
                   1272: 
                   1273:     int iSize;
                   1274:     BYTE * pb;
                   1275: 
                   1276:     pttp = (PRETOUCHTHREADPARM *) dw;
                   1277:     iSize = pttp->Len;
                   1278:     pb = pttp->Addr;
                   1279: 
                   1280:     LocalFree(pttp);
                   1281: 
                   1282:     while (iSize>0) {
                   1283:         volatile BYTE b;
                   1284:         b = *pb;
                   1285:         pb += 4096;    // move to next page.  Are they ALWAYS 4096?
                   1286:         iSize -= 4096; // and count it off
                   1287:     }
                   1288:     dprintf(("All pretouched!"));
                   1289:     return 0;
                   1290: }
                   1291: #endif //0
                   1292: 
                   1293: /****************************************************************************
                   1294:  * @doc INTERNAL
                   1295:  *
                   1296:  * @api DWORD | waveThread | Wave device auxiliary thread.
                   1297:  *
                   1298:  * @parm LPVOID | lpParameter | The thread parameter.  In our case this is a
                   1299:  *     pointer to our wave device data.
                   1300:  *
                   1301:  * @rdesc Thread return code.
                   1302:  ***************************************************************************/
                   1303: STATIC DWORD waveThread(LPVOID lpParameter)
                   1304: {
                   1305:     PWAVEALLOC pClient;
                   1306:     BOOL Terminate;
                   1307: //  DWORD dwThread;                   // garbage
                   1308: 
                   1309: 
                   1310:     Terminate = FALSE;
                   1311: 
                   1312:     pClient = (PWAVEALLOC)lpParameter;
                   1313: 
                   1314:     //
                   1315:     // Set our thread to high priority so we don't fail to pass
                   1316:     // new buffers to the device
                   1317:     //
                   1318: 
                   1319:     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
                   1320: 
                   1321:     //
                   1322:     // We start by waiting for something signalling that we've started
                   1323:     // and waiting for something to do.
                   1324:     //
                   1325: 
                   1326:     SetEvent(pClient->AuxEvent2);
                   1327:     WaitForSingleObject(pClient->AuxEvent1, INFINITE);
                   1328: 
                   1329:     //
                   1330:     // Now we're going
                   1331:     //
                   1332: 
                   1333:     for (;;) {
                   1334:         WinAssert(pClient->hDev != INVALID_HANDLE_VALUE);
                   1335: 
                   1336:         //
                   1337:         // Decode function number to perform
                   1338:         //
                   1339: 
                   1340:         switch (pClient->AuxFunction) {
                   1341:         case WaveThreadAddBuffer:
                   1342:             //
                   1343:             // Intialize bytes recorded
                   1344:             //
                   1345:             if (pClient->DeviceType == WaveInDevice) {
                   1346:                 pClient->AuxParam.pHdr->dwBytesRecorded = 0;
                   1347:             }
                   1348: 
                   1349:             //
                   1350:             // Add the buffer to our list
                   1351:             //
                   1352:             {
                   1353:                 LPWAVEHDR *pHdrSearch;
                   1354: 
                   1355:                 pClient->AuxParam.pHdr->lpNext = NULL;
                   1356: 
                   1357:                 pHdrSearch = &pClient->DeviceQueue;
                   1358:                 while (*pHdrSearch) {
                   1359:                     pHdrSearch = &(*pHdrSearch)->lpNext;
                   1360:                 }
                   1361: 
                   1362:                 *pHdrSearch = pClient->AuxParam.pHdr;
                   1363:             }
                   1364: //          {
                   1365: //               PRETOUCHTHREADPARM * pttp;
                   1366: //
                   1367: //               pttp = LocalAlloc(LMEM_FIXED,8);
                   1368: //
                   1369: //               if (pttp!=NULL) {
                   1370: //                   pttp->Addr = pClient->AuxParam.pHdr->lpData;
                   1371: //                   pttp->Len = pClient->AuxParam.pHdr->dwBufferLength;
                   1372: //                   CreateThread(NULL, 0, PreToucher, pttp, 0, &dwThread);
                   1373: //               }
                   1374: //          }
                   1375: //          Would need to declutter the system by WAITing for dead threads at some point???
                   1376: 
                   1377:             //
                   1378:             // See if we can send more to the driver
                   1379:             //
                   1380:             if (pClient->NextBuffer == NULL) {
                   1381:                 pClient->NextBuffer = pClient->AuxParam.pHdr;
                   1382:                 pClient->BufferPosition = 0;
                   1383:             }
                   1384: 
                   1385: 
                   1386: //            /* Before we waveStart, let's just try to pre-touch that which we will soon want */
                   1387: //            {
                   1388: //                PWAVEHDR pHdr = pClient->NextBuffer;
                   1389: //                DWORD dwTick = GetTickCount();
                   1390: //                PreTouch( (PBYTE)pHdr->lpData + pClient->BufferPosition
                   1391: //                        , pHdr->dwBufferLength - pClient->BufferPosition
                   1392: //                        , TRUE
                   1393: //                        );
                   1394: //                dprintf(("pre-touched out to limit. Took %d mSec", GetTickCount()-dwTick));
                   1395: //            }
                   1396: 
                   1397:             pClient->AuxReturnCode = waveStart(pClient);
                   1398:             break;
                   1399: 
                   1400:         case WaveThreadSetState:
                   1401:             //
                   1402:             // We have to make sure at least ONE buffer gets
                   1403:             // completed if we're doing input and it's input.
                   1404:             //
                   1405: 
                   1406: 
                   1407: 
                   1408:             //
                   1409:             // Set Device state.  By issuing state changes on THIS
                   1410:             // thread the calling thread can be sure that all Apc's
                   1411:             // generated by buffer completions will complete
                   1412:             // BEFORE this function completes.
                   1413:             //
                   1414: 
                   1415:             pClient->AuxReturnCode =
                   1416:                 waveSetState(pClient, pClient->AuxParam.State);
                   1417: 
                   1418: 
                   1419:             //
                   1420:             // Free the rest of our buffers if we're resetting
                   1421:             //
                   1422: 
                   1423:             if (pClient->AuxParam.State == WAVE_DD_RESET) {
                   1424:                 //
                   1425:                 // Cancel any loops
                   1426:                 //
                   1427:                 pClient->LoopHead = NULL;
                   1428: 
                   1429:                 //
                   1430:                 // This function must ALWAYS succeed
                   1431:                 // Note that waveSetState closes the device on failure
                   1432:                 //
                   1433:                 pClient->AuxReturnCode = MMSYSERR_NOERROR;
                   1434: 
                   1435:                 //
                   1436:                 // Check this worked (even if the driver's OK the
                   1437:                 // IO subsystem can fail)
                   1438:                 //
                   1439:                 WinAssert(pClient->BytesOutstanding == 0);
                   1440: 
                   1441:                 //
                   1442:                 // Free all buffers
                   1443:                 //
                   1444:                 waveFreeQ(pClient);
                   1445: 
                   1446:             } else {
                   1447:                 if (pClient->DeviceType == WaveInDevice &&
                   1448:                     pClient->AuxReturnCode == MMSYSERR_NOERROR) {
                   1449: 
                   1450:                     if (pClient->AuxParam.State == WAVE_DD_STOP) {
                   1451:                         //
                   1452:                         // We're sort of stuck - we want to complete this
                   1453:                         // buffer but we've got it tied up in the device
                   1454:                         // We'll reset it here although this erroneously
                   1455:                         // sets the position to 0
                   1456:                         //
                   1457:                         if (pClient->DeviceQueue) {
                   1458:                             while (!(pClient->DeviceQueue->dwFlags & WHDR_COMPLETE) &&
                   1459:                                    pClient->BytesOutstanding != 0) {
                   1460:                                 waveSetState(pClient, WAVE_DD_RECORD);
                   1461:                                 pClient->AuxReturnCode =
                   1462:                                     waveSetState(pClient, WAVE_DD_STOP);
                   1463:                                 if (pClient->AuxReturnCode != MMSYSERR_NOERROR) {
                   1464:                                     break;
                   1465:                                 }
                   1466:                             }
                   1467:                             if (pClient->AuxReturnCode == MMSYSERR_NOERROR) {
                   1468:                                 pClient->DeviceQueue->dwFlags |= WHDR_COMPLETE;
                   1469:                                                                 //
                   1470:                                                                 // Tidy up next buffer
                   1471:                                                                 //
                   1472:                                                                 if (pClient->NextBuffer ==
                   1473:                                                                     pClient->DeviceQueue) {
                   1474:                                                                         pClient->NextBuffer =
                   1475:                                                                             pClient->DeviceQueue->lpNext;
                   1476:                                                                     pClient->BufferPosition = 0;
                   1477:                                                             }
                   1478:                             }
                   1479:                         }
                   1480:                     } else {
                   1481:                         //
                   1482:                         // If recording restore some buffers if necessary
                   1483:                         //
                   1484:                         if (pClient->AuxParam.State == WAVE_DD_RECORD) {
                   1485:                             pClient->AuxReturnCode = waveStart(pClient);
                   1486:                         }
                   1487:                     }
                   1488:                 }
                   1489:             }
                   1490:             break;
                   1491: 
                   1492:         case WaveThreadGetData:
                   1493:             {
                   1494:                 pClient->AuxReturnCode =
                   1495:                     sndGetHandleData(pClient->hDev,
                   1496:                                      pClient->AuxParam.GetSetData.DataLen,
                   1497:                                      pClient->AuxParam.GetSetData.pData,
                   1498:                                      pClient->AuxParam.GetSetData.Function,
                   1499:                                      pClient->Event);
                   1500:             }
                   1501:             break;
                   1502: 
                   1503:         case WaveThreadSetData:
                   1504:             {
                   1505:                 pClient->AuxReturnCode =
                   1506:                     sndSetHandleData(pClient->hDev,
                   1507:                                      pClient->AuxParam.GetSetData.DataLen,
                   1508:                                      pClient->AuxParam.GetSetData.pData,
                   1509:                                      pClient->AuxParam.GetSetData.Function,
                   1510:                                      pClient->Event);
                   1511:             }
                   1512:             break;
                   1513: 
                   1514:         case WaveThreadBreakLoop:
                   1515:             if (pClient->LoopHead) {
                   1516:                 //
                   1517:                 // If we're in a loop then exit the loop at the
                   1518:                 // end of the next iteration.
                   1519:                 //
                   1520: 
                   1521:                 pClient->LoopCount = 0;
                   1522:             }
                   1523:             pClient->AuxReturnCode = MMSYSERR_NOERROR;
                   1524:             break;
                   1525: 
                   1526:         case WaveThreadClose:
                   1527:             //
                   1528:             // Try to complete.
                   1529:             // If we're completed all our buffers then we can.
                   1530:             // otherwise we can't
                   1531:             //
                   1532:             if (pClient->DeviceQueue == NULL) {
                   1533:                 pClient->AuxReturnCode = MMSYSERR_NOERROR;
                   1534:             } else {
                   1535:                 pClient->AuxReturnCode = WAVERR_STILLPLAYING;
                   1536:             }
                   1537:             break;
                   1538: 
                   1539:         case WaveThreadTerminate:
                   1540:             Terminate = TRUE;
                   1541:             break;
                   1542: 
                   1543: 
                   1544:         default:
                   1545:             WinAssert(FALSE);   // Invalid call
                   1546:             break;
                   1547:         }
                   1548:         //
                   1549:         // Trap invalid callers
                   1550:         //
                   1551:         pClient->AuxFunction = WaveThreadInvalid;
                   1552: 
                   1553:                 //
                   1554:                 // See if any Apcs need completing
                   1555:                 //
                   1556:                 waveCompleteBuffers(pClient);
                   1557: 
                   1558:         //
                   1559:         // Complete ? - don't set the event here.
                   1560:         //
                   1561:         if (Terminate) {
                   1562:             return 1;
                   1563:         }
                   1564: 
                   1565:         //
                   1566:         // Release the thread caller
                   1567:         //
                   1568:         SetEvent(pClient->AuxEvent2);
                   1569: 
                   1570:         //
                   1571:         // Wait for more !
                   1572:         //
                   1573: 
                   1574:         while (WaitForSingleObjectEx(pClient->AuxEvent1, INFINITE, TRUE) ==
                   1575:                    WAIT_IO_COMPLETION) {
                   1576:                 waveCompleteBuffers(pClient);
                   1577:         }
                   1578:     }
                   1579: 
                   1580:     return 1;      // Satisfy the compiler !
                   1581: }
                   1582: 
                   1583: 
                   1584: 
                   1585: /****************************************************************************
                   1586:  * @doc INTERNAL
                   1587:  *
                   1588:  * @api void | waveCallback | This calls DriverCallback for a WAVEHDR.
                   1589:  *
                   1590:  * @parm PWAVEALLOC | pWave | Pointer to wave device.
                   1591:  *
                   1592:  * @parm DWORD | msg | The message.
                   1593:  *
                   1594:  * @parm DWORD | dw1 | message DWORD (dw2 is always set to 0).
                   1595:  *
                   1596:  * @rdesc There is no return value.
                   1597:  ***************************************************************************/
                   1598: void waveCallback(PWAVEALLOC pWave, DWORD msg, DWORD dw1)
                   1599: {
                   1600: 
                   1601:     // invoke the callback function, if it exists.  dwFlags contains
                   1602:     // wave driver specific flags in the LOWORD and generic driver
                   1603:     // flags in the HIWORD
                   1604: 
                   1605:     if (pWave->dwCallback)
                   1606:         DriverCallback(pWave->dwCallback,       // user's callback DWORD
                   1607:                        HIWORD(pWave->dwFlags),  // callback flags
                   1608:                        pWave->hWave,            // handle to the wave device
                   1609:                        msg,                     // the message
                   1610:                        pWave->dwInstance,       // user's instance data
                   1611:                        dw1,                     // first DWORD
                   1612:                        0L);                     // second DWORD
                   1613: }
                   1614: 
                   1615: 
                   1616: 
                   1617: /****************************************************************************
                   1618: 
                   1619:     This function conforms to the standard Wave input driver message proc
                   1620:     (widMessage), which is documented in mmddk.d.
                   1621: 
                   1622: ****************************************************************************/
                   1623: DWORD APIENTRY widMessage(DWORD id, DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
                   1624: {
                   1625:     PWAVEALLOC pInClient;
                   1626:     MMRESULT mRet;
                   1627: 
                   1628:     switch (msg) {
                   1629: 
                   1630:         case WIDM_GETNUMDEVS:
                   1631:             D2(("WIDM_GETNUMDEVS"));
                   1632:             return sndGetNumDevs(WaveInDevice);
                   1633: 
                   1634:         case WIDM_GETDEVCAPS:
                   1635:             D2(("WIDM_GETDEVCAPS"));
                   1636:             return waveGetDevCaps(id, WaveInDevice, (LPBYTE)dwParam1,
                   1637:                                   (DWORD)dwParam2);
                   1638: 
                   1639:         case WIDM_OPEN:
                   1640:             D2(("WIDM_OPEN"));
                   1641:             return waveOpen(WaveInDevice, id, dwUser, dwParam1, dwParam2);
                   1642: 
                   1643:         case WIDM_CLOSE:
                   1644:             D2(("WIDM_CLOSE"));
                   1645:             pInClient = (PWAVEALLOC)dwUser;
                   1646: 
                   1647:             //
                   1648:             // Call our task to see if it's ready to complete
                   1649:             //
                   1650:             mRet = waveThreadCall(WaveThreadClose, pInClient);
                   1651:             if (mRet != MMSYSERR_NOERROR) {
                   1652:                 return mRet;
                   1653:             }
                   1654: 
                   1655:             waveCallback(pInClient, WIM_CLOSE, 0L);
                   1656: 
                   1657:             //
                   1658:             // Close our device
                   1659:             //
                   1660:             if (pInClient->hDev != INVALID_HANDLE_VALUE) {
                   1661:                 CloseHandle(pInClient->hDev);
                   1662:                 EnterCriticalSection(&mmDrvCritSec);
                   1663:                 pInClient->hDev = INVALID_HANDLE_VALUE;
                   1664:                 LeaveCriticalSection(&mmDrvCritSec);
                   1665:             }
                   1666: 
                   1667:             return MMSYSERR_NOERROR;
                   1668: 
                   1669:         case WIDM_ADDBUFFER:
                   1670:             D2(("WIDM_ADDBUFFER"));
                   1671:             WinAssert(dwParam1 != 0);
                   1672:             WinAssert(!(((LPWAVEHDR)dwParam1)->dwFlags & ~(WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP)));
                   1673: 
                   1674:             ((LPWAVEHDR)dwParam1)->dwFlags &= (WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED);
                   1675: 
                   1676:             WinAssert(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_PREPARED);
                   1677: 
                   1678:             // check if it's been prepared
                   1679:             if (!(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_PREPARED))
                   1680:                 return WAVERR_UNPREPARED;
                   1681: 
                   1682:             WinAssert(!(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_INQUEUE));
                   1683: 
                   1684:             // if it is already in our Q, then we cannot do this
                   1685:             if ( ((LPWAVEHDR)dwParam1)->dwFlags & WHDR_INQUEUE )
                   1686:                 return ( WAVERR_STILLPLAYING );
                   1687: 
                   1688:             // store the pointer to my WAVEALLOC structure in the wavehdr
                   1689:             pInClient = (PWAVEALLOC)dwUser;
                   1690:             ((LPWAVEHDR)dwParam1)->reserved = (DWORD)(LPSTR)pInClient;
                   1691: 
                   1692:             return waveWrite((LPWAVEHDR)dwParam1, pInClient);
                   1693: 
                   1694:         case WIDM_STOP:
                   1695:             D2(("WIDM_PAUSE"));
                   1696:             pInClient = (PWAVEALLOC)dwUser;
                   1697:             pInClient->AuxParam.State = WAVE_DD_STOP;
                   1698:             return waveThreadCall(WaveThreadSetState, pInClient);
                   1699: 
                   1700:         case WIDM_START:
                   1701:             D2(("WIDM_RESTART"));
                   1702:             pInClient = (PWAVEALLOC)dwUser;
                   1703:             pInClient->AuxParam.State = WAVE_DD_RECORD;
                   1704:             return waveThreadCall(WaveThreadSetState, pInClient);
                   1705: 
                   1706:         case WIDM_RESET:
                   1707:             D2(("WIDM_RESET"));
                   1708:             pInClient = (PWAVEALLOC)dwUser;
                   1709:             pInClient->AuxParam.State = WAVE_DD_RESET;
                   1710:             return waveThreadCall(WaveThreadSetState, pInClient);
                   1711: 
                   1712:         case WIDM_GETPOS:
                   1713:             D2(("WIDM_GETPOS"));
                   1714:             pInClient = (PWAVEALLOC)dwUser;
                   1715:             return waveGetPos(pInClient, (LPMMTIME)dwParam1, dwParam2);
                   1716: 
                   1717:         default:
                   1718:             return MMSYSERR_NOTSUPPORTED;
                   1719:     }
                   1720: 
                   1721:     //
                   1722:     // Should not get here
                   1723:     //
                   1724: 
                   1725:     WinAssert(0);
                   1726:     return MMSYSERR_NOTSUPPORTED;
                   1727: }
                   1728: 
                   1729: /****************************************************************************
                   1730: 
                   1731:     This function conforms to the standard Wave output driver message proc
                   1732:     (wodMessage), which is documented in mmddk.h.
                   1733: 
                   1734: ****************************************************************************/
                   1735: DWORD APIENTRY wodMessage(DWORD id, DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
                   1736: {
                   1737:     PWAVEALLOC pOutClient;
                   1738:     MMRESULT mRet;
                   1739: 
                   1740:     switch (msg) {
                   1741:         case WODM_GETNUMDEVS:
                   1742:             D2(("WODM_GETNUMDEVS"));
                   1743:             return sndGetNumDevs(WaveOutDevice);
                   1744: 
                   1745:         case WODM_GETDEVCAPS:
                   1746:             D2(("WODM_GETDEVCAPS"));
                   1747:             return waveGetDevCaps(id, WaveOutDevice, (LPBYTE)dwParam1,
                   1748:                                   (DWORD)dwParam2);
                   1749: 
                   1750:         case WODM_OPEN:
                   1751:             D2(("WODM_OPEN"));
                   1752:             return waveOpen(WaveOutDevice, id, dwUser, dwParam1, dwParam2);
                   1753: 
                   1754:         case WODM_CLOSE:
                   1755:             D2(("WODM_CLOSE"));
                   1756:             pOutClient = (PWAVEALLOC)dwUser;
                   1757: 
                   1758:             //
                   1759:             // Call our task to see if it's ready to complete
                   1760:             //
                   1761:             mRet = waveThreadCall(WaveThreadClose, pOutClient);
                   1762:             if (mRet != MMSYSERR_NOERROR) {
                   1763:                 return mRet;
                   1764:             }
                   1765: 
                   1766:             waveCallback(pOutClient, WOM_CLOSE, 0L);
                   1767: 
                   1768:             //
                   1769:             // Close our device
                   1770:             //
                   1771:             if (pOutClient->hDev != INVALID_HANDLE_VALUE) {
                   1772:                 CloseHandle(pOutClient->hDev);
                   1773: 
                   1774:                 EnterCriticalSection(&mmDrvCritSec);
                   1775:                 pOutClient->hDev = INVALID_HANDLE_VALUE;
                   1776:                 LeaveCriticalSection(&mmDrvCritSec);
                   1777:             }
                   1778: 
                   1779:             return MMSYSERR_NOERROR;
                   1780: 
                   1781:         case WODM_WRITE:
                   1782:             D2(("WODM_WRITE"));
                   1783:             WinAssert(dwParam1 != 0);
                   1784:             WinAssert(!(((LPWAVEHDR)dwParam1)->dwFlags &
                   1785:                      ~(WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|
                   1786:                        WHDR_BEGINLOOP|WHDR_ENDLOOP)));
                   1787: 
                   1788:             ((LPWAVEHDR)dwParam1)->dwFlags &=
                   1789:                 (WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|
                   1790:                  WHDR_BEGINLOOP|WHDR_ENDLOOP);
                   1791: 
                   1792:             WinAssert(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_PREPARED);
                   1793: 
                   1794:             // check if it's been prepared
                   1795:             if (!(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_PREPARED))
                   1796:                 return WAVERR_UNPREPARED;
                   1797: 
                   1798:             WinAssert(!(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_INQUEUE));
                   1799: 
                   1800:             // if it is already in our Q, then we cannot do this
                   1801:             if ( ((LPWAVEHDR)dwParam1)->dwFlags & WHDR_INQUEUE )
                   1802:                 return ( WAVERR_STILLPLAYING );
                   1803: 
                   1804:             // store the pointer to my WAVEALLOC structure in the wavehdr
                   1805:             pOutClient = (PWAVEALLOC)dwUser;
                   1806:             ((LPWAVEHDR)dwParam1)->reserved = (DWORD)(LPSTR)pOutClient;
                   1807: 
                   1808:             return waveWrite((LPWAVEHDR)dwParam1, pOutClient);
                   1809: 
                   1810: 
                   1811:         case WODM_PAUSE:
                   1812:             D2(("WODM_PAUSE"));
                   1813:             pOutClient = (PWAVEALLOC)dwUser;
                   1814:             pOutClient->AuxParam.State = WAVE_DD_STOP;
                   1815:             return waveThreadCall(WaveThreadSetState, pOutClient);
                   1816: 
                   1817:         case WODM_RESTART:
                   1818:             D2(("WODM_RESTART"));
                   1819:             pOutClient = (PWAVEALLOC)dwUser;
                   1820:             pOutClient->AuxParam.State = WAVE_DD_PLAY;
                   1821:             return waveThreadCall(WaveThreadSetState, pOutClient);
                   1822: 
                   1823:         case WODM_RESET:
                   1824:             D2(("WODM_RESET"));
                   1825:             pOutClient = (PWAVEALLOC)dwUser;
                   1826:             pOutClient->AuxParam.State = WAVE_DD_RESET;
                   1827:             return waveThreadCall(WaveThreadSetState, pOutClient);
                   1828: 
                   1829:         case WODM_BREAKLOOP:
                   1830:             pOutClient = (PWAVEALLOC)dwUser;
                   1831:             D2(("WODM_BREAKLOOP"));
                   1832:             return waveThreadCall(WaveThreadBreakLoop, pOutClient);
                   1833: 
                   1834: 
                   1835:         case WODM_GETPOS:
                   1836:             D2(("WODM_GETPOS"));
                   1837:             pOutClient = (PWAVEALLOC)dwUser;
                   1838:             return waveGetPos(pOutClient, (LPMMTIME)dwParam1, dwParam2);
                   1839: 
                   1840:         case WODM_SETPITCH:
                   1841:             D2(("WODM_SETPITCH"));
                   1842:             pOutClient = (PWAVEALLOC)dwUser;
                   1843:             pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
                   1844:             pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
                   1845:             pOutClient->AuxParam.GetSetData.Function = IOCTL_WAVE_SET_PITCH;
                   1846:             return waveThreadCall(WaveThreadSetData, pOutClient);
                   1847: 
                   1848:         case WODM_SETVOLUME:
                   1849:             D2(("WODM_SETVOLUME"));
                   1850:             //pOutClient = (PWAVEALLOC)dwUser;
                   1851:             //pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
                   1852:             //pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
                   1853:             //pOutClient->AuxParam.GetSetData.Function = IOCTL_WAVE_SET_VOLUME;
                   1854:             //return waveThreadCall(WaveThreadSetData, pOutClient);
                   1855: 
                   1856:             {
                   1857:                 //
                   1858:                 // Translate to device volume structure
                   1859:                 //
                   1860: 
                   1861:                 WAVE_DD_VOLUME Volume;
                   1862:                 Volume.Left = LOWORD(dwParam1) << 16;
                   1863:                 Volume.Right = HIWORD(dwParam1) << 16;
                   1864: 
                   1865:                 return sndSetData(WaveOutDevice, id, sizeof(Volume),
                   1866:                                   (PBYTE)&Volume, IOCTL_WAVE_SET_VOLUME);
                   1867:             }
                   1868: 
                   1869: 
                   1870:         case WODM_SETPLAYBACKRATE:
                   1871:             D2(("WODM_SETPLAYBACKRATE"));
                   1872:             pOutClient = (PWAVEALLOC)dwUser;
                   1873:             pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
                   1874:             pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
                   1875:             pOutClient->AuxParam.GetSetData.Function =
                   1876:                 IOCTL_WAVE_SET_PLAYBACK_RATE;
                   1877:             return waveThreadCall(WaveThreadSetData, pOutClient);
                   1878: 
                   1879:         case WODM_GETPITCH:
                   1880:             D2(("WODM_GETPITCH"));
                   1881:             pOutClient = (PWAVEALLOC)dwUser;
                   1882:             pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
                   1883:             pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
                   1884:             pOutClient->AuxParam.GetSetData.Function = IOCTL_WAVE_GET_PITCH;
                   1885:             return waveThreadCall(WaveThreadGetData, pOutClient);
                   1886: 
                   1887:         case WODM_GETVOLUME:
                   1888:             D2(("WODM_GETVOLUME"));
                   1889:             //pOutClient = (PWAVEALLOC)dwUser;
                   1890:             //pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
                   1891:             //pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
                   1892:             //pOutClient->AuxParam.GetSetData.Function = IOCTL_WAVE_GET_VOLUME;
                   1893:             //return waveThreadCall(WaveThreadGetData, pOutClient);
                   1894: 
                   1895:             {
                   1896:                 //
                   1897:                 // Translate to device volume structure
                   1898:                 //
                   1899: 
                   1900:                 WAVE_DD_VOLUME Volume;
                   1901:                 DWORD rc;
                   1902: 
                   1903:                 rc = sndGetData(WaveOutDevice, id, sizeof(Volume),
                   1904:                                 (PBYTE)&Volume, IOCTL_WAVE_GET_VOLUME);
                   1905: 
                   1906:                 if (rc == MMSYSERR_NOERROR) {
                   1907:                     *(LPDWORD)dwParam1 =
                   1908:                         (DWORD)MAKELONG(HIWORD(Volume.Left),
                   1909:                                         HIWORD(Volume.Right));
                   1910:                 }
                   1911: 
                   1912:                 return rc;
                   1913:             }
                   1914: 
                   1915:         case WODM_GETPLAYBACKRATE:
                   1916:             D2(("WODM_GETPLAYBACKRATE"));
                   1917:             pOutClient = (PWAVEALLOC)dwUser;
                   1918:             pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
                   1919:             pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
                   1920:             pOutClient->AuxParam.GetSetData.Function =
                   1921:                 IOCTL_WAVE_GET_PLAYBACK_RATE;
                   1922:             return waveThreadCall(WaveThreadGetData, pOutClient);
                   1923: 
                   1924:         default:
                   1925:             return MMSYSERR_NOTSUPPORTED;
                   1926:     }
                   1927: 
                   1928:     //
                   1929:     // Should not get here
                   1930:     //
                   1931: 
                   1932:     WinAssert(0);
                   1933:     return MMSYSERR_NOTSUPPORTED;
                   1934: }

unix.superglobalmegacorp.com

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