[ros-diffs] [silverblade] 27384: Removing WDMAUD until I figure out how it can be implemented properly (this will not have any adverse effects as it doesn't actually work yet.) Also replacing MMDRV with a rewritten version as it appears to contain big chunks copied directly from NT4 DDK examples!

silverblade at svn.reactos.org silverblade at svn.reactos.org
Wed Jul 4 12:17:48 CEST 2007


Author: silverblade
Date: Wed Jul  4 14:17:48 2007
New Revision: 27384

URL: http://svn.reactos.org/svn/reactos?rev=27384&view=rev
Log:
Removing WDMAUD until I figure out how it can be implemented properly
(this will not have any adverse effects as it doesn't actually work 
yet.) Also replacing MMDRV with a rewritten version as it appears to
contain big chunks copied directly from NT4 DDK examples!


Added:
    trunk/reactos/dll/win32/mmdrv/TODO
    trunk/reactos/dll/win32/mmdrv/common.c
    trunk/reactos/dll/win32/mmdrv/kernel.c
    trunk/reactos/dll/win32/mmdrv/mme.c
    trunk/reactos/dll/win32/mmdrv/mmioctl.h
    trunk/reactos/dll/win32/mmdrv/session.c
    trunk/reactos/dll/win32/mmdrv/wave_io.c
Removed:
    trunk/reactos/dll/win32/wdmaud/
Modified:
    trunk/reactos/dll/win32/mmdrv/entry.c
    trunk/reactos/dll/win32/mmdrv/mmdrv.def
    trunk/reactos/dll/win32/mmdrv/mmdrv.h
    trunk/reactos/dll/win32/mmdrv/mmdrv.rbuild
    trunk/reactos/dll/win32/mmdrv/wave.c

Added: trunk/reactos/dll/win32/mmdrv/TODO
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/TODO?rev=27384&view=auto
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/TODO (added)
+++ trunk/reactos/dll/win32/mmdrv/TODO Wed Jul  4 14:17:48 2007
@@ -1,0 +1,4 @@
+Jan 2007 TODO list
+
+* Set WHDR_COMPLETE when WriteFileEx APC is called
+* Check for WHDR_COMPLETE flag when completing buffers outside APC

Added: trunk/reactos/dll/win32/mmdrv/common.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/common.c?rev=27384&view=auto
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/common.c (added)
+++ trunk/reactos/dll/win32/mmdrv/common.c Wed Jul  4 14:17:48 2007
@@ -1,0 +1,258 @@
+/*
+ *
+ * COPYRIGHT:            See COPYING in the top level directory
+ * PROJECT:              ReactOS Multimedia
+ * FILE:                 dll/win32/mmdrv/common.c
+ * PURPOSE:              Multimedia User Mode Driver (Common functions)
+ * PROGRAMMER:           Andrew Greenwood
+ * UPDATE HISTORY:
+ *                       Jan 14, 2007: Created
+ */
+
+#include <mmdrv.h>
+
+/*
+    Translates errors to MMRESULT codes.
+*/
+
+MMRESULT
+ErrorToMmResult(UINT error_code)
+{
+    switch ( error_code )
+    {
+        case NO_ERROR :
+        case ERROR_IO_PENDING :
+            return MMSYSERR_NOERROR;
+
+        case ERROR_BUSY :
+            return MMSYSERR_ALLOCATED;
+
+        case ERROR_NOT_SUPPORTED :
+        case ERROR_INVALID_FUNCTION :
+            return MMSYSERR_NOTSUPPORTED;
+
+        case ERROR_NOT_ENOUGH_MEMORY :
+            return MMSYSERR_NOMEM;
+
+        case ERROR_ACCESS_DENIED :
+            return MMSYSERR_BADDEVICEID;
+
+        case ERROR_INSUFFICIENT_BUFFER :
+            return MMSYSERR_INVALPARAM;
+    };
+
+    /* If all else fails, it's just a plain old error */
+
+    return MMSYSERR_ERROR;
+}
+
+
+/*
+    Obtains a device count for a specific kind of device.
+*/
+
+DWORD
+GetDeviceCount(DeviceType device_type)
+{
+    UINT index = 0;
+    HANDLE handle;
+
+    /* Cycle through devices until an error occurs */
+
+    while ( OpenKernelDevice(device_type, index, GENERIC_READ, &handle) == MMSYSERR_NOERROR )
+    {
+        CloseHandle(handle);
+        index ++;
+    }
+
+    DPRINT("Found %d devices of type %d\n", index, device_type);
+
+    return index;
+}
+
+
+/*
+    Obtains device capabilities. This could either be done as individual
+    functions for wave, MIDI and aux, or like this. I chose this method as
+    it centralizes everything.
+*/
+
+DWORD
+GetDeviceCapabilities(
+    DeviceType device_type,
+    DWORD device_id,
+    PVOID capabilities,
+    DWORD capabilities_size)
+{
+    MMRESULT result;
+    DWORD ioctl;
+    HANDLE handle;
+    DWORD bytes_returned;
+    BOOL device_io_result;
+
+    ASSERT(capabilities);
+
+    /* Choose the right IOCTL for the job */
+
+    if ( IsWaveDevice(device_type) )
+        ioctl = IOCTL_WAVE_GET_CAPABILITIES;
+    else if ( IsMidiDevice(device_type) )
+        ioctl = IOCTL_MIDI_GET_CAPABILITIES;
+    else if ( IsAuxDevice(device_type) )
+        return MMSYSERR_NOTSUPPORTED; /* TODO */
+    else
+        return MMSYSERR_NOTSUPPORTED;
+
+    result = OpenKernelDevice(device_type,
+                              device_id,
+                              GENERIC_READ,
+                              &handle);
+
+    if ( result != MMSYSERR_NOERROR )
+    {
+        DPRINT("Failed to open kernel device\n");
+        return result;
+    }
+
+    device_io_result = DeviceIoControl(handle,
+                                       ioctl,
+                                       NULL,
+                                       0,
+                                       (LPVOID) capabilities,
+                                       capabilities_size,
+                                       &bytes_returned,
+                                       NULL);
+
+    /* Translate result */
+
+    if ( device_io_result )
+        result = MMSYSERR_NOERROR;
+    else
+        result = ErrorToMmResult(GetLastError());
+
+    /* Clean up and return */
+
+    CloseKernelDevice(handle);
+
+    return result;
+}
+
+
+/*
+    A wrapper around OpenKernelDevice that creates a session,
+    opens the kernel device, initializes session data and notifies
+    the client (application) that the device has been opened. Again,
+    this supports any device type and the only real difference is
+    the open descriptor.
+*/
+
+DWORD
+OpenDevice(
+    DeviceType device_type,
+    DWORD device_id,
+    PVOID open_descriptor,
+    DWORD flags,
+    DWORD private_handle)
+{
+    SessionInfo* session_info;
+    MMRESULT result;
+    DWORD message;
+
+    /* This will automatically check for duplicate sessions */
+    result = CreateSession(device_type, device_id, &session_info);
+
+    if ( result != MMSYSERR_NOERROR )
+    {
+        DPRINT("Couldn't allocate session info\n");
+        return result;
+    }
+
+    result = OpenKernelDevice(device_type,
+                              device_id,
+                              GENERIC_READ,
+                              &session_info->kernel_device_handle);
+
+    if ( result != MMSYSERR_NOERROR )
+    {
+        DPRINT("Failed to open kernel device\n");
+        DestroySession(session_info);
+        return result;
+    }
+
+    /* Set common session data */
+
+    session_info->flags = flags;
+
+    /* Set wave/MIDI specific data */
+
+    if ( IsWaveDevice(device_type) )
+    {
+        LPWAVEOPENDESC wave_open_desc = (LPWAVEOPENDESC) open_descriptor;
+        session_info->callback = wave_open_desc->dwCallback;
+        session_info->mme_wave_handle = wave_open_desc->hWave;
+        session_info->app_user_data = wave_open_desc->dwInstance;
+    }
+    else
+    {
+        DPRINT("Only wave devices are supported at present!\n");
+        DestroySession(session_info);
+        return MMSYSERR_NOTSUPPORTED;
+    }
+
+    /* Start the processing thread */
+
+    result = StartSessionThread(session_info);
+
+    if ( result != MMSYSERR_NOERROR )
+    {
+        DestroySession(session_info);
+        return result;
+    }
+
+    /* Store the session info */
+
+    *((SessionInfo**)private_handle) = session_info;
+
+    /* Send the right message */
+
+    message = (device_type == WaveOutDevice) ? WOM_OPEN :
+              (device_type == WaveInDevice) ? WIM_OPEN :
+              (device_type == MidiOutDevice) ? MOM_OPEN :
+              (device_type == MidiInDevice) ? MIM_OPEN : 0xFFFFFFFF;
+
+    NotifyClient(session_info, message, 0, 0);
+
+    return MMSYSERR_NOERROR;
+}
+
+
+/*
+    Attempts to close a device. This can fail if playback/recording has
+    not been stopped. We need to make sure it's safe to destroy the
+    session as well (mainly by killing the session thread.)
+*/
+
+DWORD
+CloseDevice(
+    DWORD private_handle)
+{
+    MMRESULT result;
+    SessionInfo* session_info = (SessionInfo*) private_handle;
+    /* TODO: Maybe this is best off inside the playback thread? */
+
+    ASSERT(session_info);
+
+    result = CallSessionThread(session_info, WODM_CLOSE, 0);
+
+    if ( result == MMSYSERR_NOERROR )
+    {
+        /* TODO: Wait for it to be safe to terminate */
+
+        CloseKernelDevice(session_info->kernel_device_handle);
+
+        DestroySession(session_info);
+    }
+
+    return result;
+}
+

Modified: trunk/reactos/dll/win32/mmdrv/entry.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/entry.c?rev=27384&r1=27383&r2=27384&view=diff
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/entry.c (original)
+++ trunk/reactos/dll/win32/mmdrv/entry.c Wed Jul  4 14:17:48 2007
@@ -2,68 +2,42 @@
  *
  * COPYRIGHT:            See COPYING in the top level directory
  * PROJECT:              ReactOS Multimedia
- * FILE:                 lib/mmdrv/entry.c
- * PURPOSE:              Multimedia User Mode Driver
+ * FILE:                 dll/win32/mmdrv/entry.c
+ * PURPOSE:              Multimedia User Mode Driver (DriverProc)
  * PROGRAMMER:           Andrew Greenwood
- *                       Aleksey Bragin
  * UPDATE HISTORY:
- *                       Jan 30, 2004: Imported into ReactOS tree (Greenwood)
- *                       Mar 16, 2004: Cleaned up a bit (Bragin)
+ *                       Jan 14, 2007: Created
  */
 
+#include <mmdrv.h>
 
-#include "mmdrv.h"
 
-#define NDEBUG
-#include <debug.h>
+/*
+    Nothing particularly special happens here.
 
-#define EXPORT __declspec(dllexport)
+    Back in the days of Windows 3.1, we would do something more useful here,
+    as this is effectively the old-style equivalent of NT's "DriverEntry",
+    though far more primitive.
 
-CRITICAL_SECTION DriverSection;
+    In summary, we just implement to satisfy the MME API (winmm) requirements.
+*/
 
-APIENTRY LONG DriverProc(DWORD DriverID, HANDLE DriverHandle, UINT Message,
-                LONG Param1, LONG Param2)
+LONG
+DriverProc(
+    DWORD driver_id,
+    HANDLE driver_handle,
+    UINT message,
+    LONG parameter1,
+    LONG parameter2)
 {
-    DPRINT("DriverProc\n");
-
-//    HINSTANCE Module;
-
-    switch(Message)
+    switch ( message )
     {
         case DRV_LOAD :
             DPRINT("DRV_LOAD\n");
-            return TRUE; // dont need to do any more
-/*            
-            Module = GetDriverModuleHandle(DriverHandle);
-
-        // Create our process heap
-        Heap = GetProcessHeap();
-        if (Heap == NULL)
-            return FALSE;
-
-        DisableThreadLibraryCalls(Module);
-        InitializeCriticalSection(&CS);
-
-        //
-        // Load our device list
-        //
-
-//        if (sndFindDevices() != MMSYSERR_NOERROR) {
-//            DeleteCriticalSection(&mmDrvCritSec);
-//            return FALSE;
-//        }
-
-    return TRUE;
-*/
-//            return 1L;
+            return 1L;
 
         case DRV_FREE :
             DPRINT("DRV_FREE\n");
-
-//            TerminateMidi();
-//            TerminateWave();
-
-//            DeleteCriticalSection(&CS);
             return 1L;
 
         case DRV_OPEN :
@@ -82,6 +56,11 @@
             DPRINT("DRV_DISABLE\n");
             return 1L;
 
+        /*
+            We don't provide configuration capabilities. This used to be
+            for things like I/O port, IRQ, DMA settings, etc.
+        */
+
         case DRV_QUERYCONFIGURE :
             DPRINT("DRV_QUERYCONFIGURE\n");
             return 0L;
@@ -93,44 +72,11 @@
         case DRV_INSTALL :
             DPRINT("DRV_INSTALL\n");
             return DRVCNF_RESTART;
+    };
 
-        default :
-            DPRINT("?\n");
-            return DefDriverProc(DriverID, DriverHandle, Message, Param1, Param2);
-    };
+    return DefDriverProc(driver_id,
+                         driver_handle,
+                         message,
+                         parameter1,
+                         parameter2);
 }
-
-
-BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved)
-{
-    DPRINT("DllMain called!\n");
-
-    if (Reason == DLL_PROCESS_ATTACH)
-    {
-        DisableThreadLibraryCalls(hInstance);
-
-        // Create our heap
-        Heap = HeapCreate(0, 800, 0);
-        if (Heap == NULL)
-            return FALSE;
-
-        InitializeCriticalSection(&CS);
-
-        // OK to do this now??        
-        FindDevices();
-
-    }
-    else if (Reason == DLL_PROCESS_DETACH)
-    {
-        // We need to do cleanup here...
-//        TerminateMidi();
-//        TerminateWave();
-
-        DeleteCriticalSection(&CS);
-        HeapDestroy(Heap);
-    }
-    
-    return TRUE;
-}
-
-/* EOF */

Added: trunk/reactos/dll/win32/mmdrv/kernel.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/kernel.c?rev=27384&view=auto
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/kernel.c (added)
+++ trunk/reactos/dll/win32/mmdrv/kernel.c Wed Jul  4 14:17:48 2007
@@ -1,0 +1,206 @@
+/*
+ *
+ * COPYRIGHT:            See COPYING in the top level directory
+ * PROJECT:              ReactOS Multimedia
+ * FILE:                 dll/win32/mmdrv/kernel.c
+ * PURPOSE:              Multimedia User Mode Driver (kernel interface)
+ * PROGRAMMER:           Andrew Greenwood
+ * UPDATE HISTORY:
+ *                       Jan 14, 2007: Created
+ */
+
+#include <mmdrv.h>
+
+/*
+    Devices that we provide access to follow a standard naming convention.
+    The first wave output, for example, appears as \Device\WaveOut0
+
+    I'm not entirely certain how drivers find a free name to use, or why
+    we need to strip the leading \Device from it when opening, but hey...
+*/
+
+MMRESULT
+CobbleDeviceName(
+    DeviceType device_type,
+    DWORD device_id,
+    PWCHAR out_device_name)
+{
+    WCHAR base_device_name[MAX_DEVICE_NAME_LENGTH];
+
+    /* Work out the base name from the device type */
+
+    switch ( device_type )
+    {
+        case WaveOutDevice :
+            wsprintf(base_device_name, L"%ls", WAVE_OUT_DEVICE_NAME);
+            break;
+
+        case WaveInDevice :
+            wsprintf(base_device_name, L"%ls", WAVE_IN_DEVICE_NAME);
+            break;
+
+        case MidiOutDevice :
+            wsprintf(base_device_name, L"%ls", MIDI_OUT_DEVICE_NAME);
+            break;
+
+        case MidiInDevice :
+            wsprintf(base_device_name, L"%ls", MIDI_IN_DEVICE_NAME);
+            break;
+
+        case AuxDevice :
+            wsprintf(base_device_name, L"%ls", AUX_DEVICE_NAME);
+            break;
+
+        default :
+            return MMSYSERR_BADDEVICEID;
+    };
+
+    /* Now append the device number, removing the leading \Device */
+
+    wsprintf(out_device_name,
+             L"\\\\.%ls%d",
+             base_device_name + strlen("\\Device"),
+             device_id);
+
+    return MMSYSERR_NOERROR;
+}
+
+
+/*
+    Takes a device type (eg: WaveOutDevice), a device ID, desired access and
+    a pointer to a location that will store the handle of the opened "file" if
+    the function succeeds.
+
+    The device type and ID are converted into a device name using the above
+    function.
+*/
+
+MMRESULT
+OpenKernelDevice(
+    DeviceType device_type,
+    DWORD device_id,
+    DWORD access,
+    HANDLE* handle)
+{
+    MMRESULT result;
+    WCHAR device_name[MAX_DEVICE_NAME_LENGTH];
+    DWORD open_flags = 0;
+
+    ASSERT(handle);
+
+    /* Glue the base device name and the ID together */
+
+    result = CobbleDeviceName(device_type, device_id, device_name);
+
+    DPRINT("Opening kernel device %ls\n", device_name);
+
+    if ( result != MMSYSERR_NOERROR )
+        return result;
+
+    /* We want overlapped I/O when writing */
+
+    if ( access != GENERIC_READ )
+        open_flags = FILE_FLAG_OVERLAPPED;
+
+    /* Now try opening... */
+
+    *handle = CreateFile(device_name,
+                         access,
+                         FILE_SHARE_WRITE,
+                         NULL,
+                         OPEN_EXISTING,
+                         open_flags,
+                         NULL);
+
+    if ( *handle == INVALID_HANDLE_VALUE )
+        return ErrorToMmResult(GetLastError());
+
+    return MMSYSERR_NOERROR;
+}
+
+
+/*
+    Just an alias for the benefit of having a pair of functions ;)
+*/
+
+void
+CloseKernelDevice(HANDLE device_handle)
+{
+    CloseHandle(device_handle);
+}
+
+
+MMRESULT
+SetDeviceData(
+    HANDLE device_handle,
+    DWORD ioctl,
+    PBYTE input_buffer,
+    DWORD buffer_size)
+{
+    DPRINT("SetDeviceData\n");
+    /* TODO */
+    return 0;
+}
+
+
+MMRESULT
+GetDeviceData(
+    HANDLE device_handle,
+    DWORD ioctl,
+    PBYTE output_buffer,
+    DWORD buffer_size)
+{
+    OVERLAPPED overlap;
+    DWORD bytes_returned;
+    BOOL success;
+    DWORD transfer;
+
+    DPRINT("GetDeviceData\n");
+
+    memset(&overlap, 0, sizeof(overlap));
+
+    overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+    if ( ! overlap.hEvent )
+        return MMSYSERR_NOMEM;
+
+    success = DeviceIoControl(device_handle,
+                              ioctl,
+                              NULL,
+                              0,
+                              output_buffer,
+                              buffer_size,
+                              &bytes_returned,
+                              &overlap);
+
+    if ( ! success )
+    {
+        if ( GetLastError() == ERROR_IO_PENDING )
+        {
+            if ( ! GetOverlappedResult(device_handle, &overlap, &transfer, TRUE) )
+            {
+                CloseHandle(overlap.hEvent);
+                return ErrorToMmResult(GetLastError());
+            }
+        }
+        else
+        {
+            CloseHandle(overlap.hEvent);
+            return ErrorToMmResult(GetLastError());
+        }
+    }
+
+    while ( TRUE )
+    {
+        SetEvent(overlap.hEvent);
+
+        if ( WaitForSingleObjectEx(overlap.hEvent, 0, TRUE) != WAIT_IO_COMPLETION )
+        {
+            break;
+        }
+    }
+
+    CloseHandle(overlap.hEvent);
+
+    return MMSYSERR_NOERROR;
+}

Modified: trunk/reactos/dll/win32/mmdrv/mmdrv.def
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/mmdrv.def?rev=27384&r1=27383&r2=27384&view=diff
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/mmdrv.def (original)
+++ trunk/reactos/dll/win32/mmdrv/mmdrv.def Wed Jul  4 14:17:48 2007
@@ -7,8 +7,8 @@
 LIBRARY mmdrv.dll
 EXPORTS
 DriverProc at 20
-widMessage at 20
+;widMessage at 20
 wodMessage at 20
-midMessage at 20
-modMessage at 20
-auxMessage at 20
+;midMessage at 20
+;modMessage at 20
+;auxMessage at 20

Modified: trunk/reactos/dll/win32/mmdrv/mmdrv.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/mmdrv.h?rev=27384&r1=27383&r2=27384&view=diff
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/mmdrv.h (original)
+++ trunk/reactos/dll/win32/mmdrv/mmdrv.h Wed Jul  4 14:17:48 2007
@@ -2,117 +2,337 @@
  *
  * COPYRIGHT:            See COPYING in the top level directory
  * PROJECT:              ReactOS Multimedia
- * FILE:                 lib/mmdrv/mmdrv.h
+ * FILE:                 dll/win32/mmdrv/mmdrv.h
  * PURPOSE:              Multimedia User Mode Driver (header)
  * PROGRAMMER:           Andrew Greenwood
  *                       Aleksey Bragin
  * UPDATE HISTORY:
  *                       Jan 30, 2004: Imported into ReactOS tree
+ *                       Jan 10, 2007: Rewritten and tidied up
  */
 
-#ifndef __INCLUDES_MMDRV_H__
-#define __INCLUDES_MMDRV_H__
-
-//#define UNICODE
-
-#define EXPORT __declspec(dllexport)
-
+#ifndef MMDRV_H
+#define MMDRV_H
+
+#include <mmioctl.h>
+#include <mmddk.h>
 
 #include <stdio.h>
-#include <windows.h>
-#include <mmsystem.h>
-#include <mmddk.h>
-
-// This needs to be done to get winioctl.h to work:
-//typedef unsigned __int64 DWORD64, *PDWORD64;
-
-#include <winioctl.h>
-//#include "mmddk.h"
-
-#include "mmdef.h"
-
-ULONG DbgPrint(PCCH Format, ...);
-
-/*
-#define SOUND_MAX_DEVICE_NAME 1024   // GUESSWORK
-#define SOUND_MAX_DEVICES 256       // GUESSWORK
-*/
-
-// If the root is \Device and the Device type is
-// WaveIn and the device number is 2, the full name is \Device\WaveIn2
-
-#define WAVE_IN_DEVICE_NAME     "\\Device\\WaveIn"
-#define WAVE_IN_DEVICE_NAME_U  L"\\Device\\WaveIn"
-#define WAVE_OUT_DEVICE_NAME    "\\Device\\WaveOut"
-#define WAVE_OUT_DEVICE_NAME_U L"\\Device\\WaveOut"
-
-#define MIDI_IN_DEVICE_NAME     "\\Device\\MidiIn"
-#define MIDI_IN_DEVICE_NAME_U  L"\\Device\\MidiIn"
-#define MIDI_OUT_DEVICE_NAME    "\\Device\\MidiOut"
-#define MIDI_OUT_DEVICE_NAME_U L"\\Device\\MidiOut"
-
-#define AUX_DEVICE_NAME     "\\Device\\MMAux"
-#define AUX_DEVICE_NAME_U  L"\\Device\\MMAux"
-
-/*
-#define IOCTL_SOUND_BASE    FILE_DEVICE_SOUND
-#define IOCTL_WAVE_BASE     0x0000
-#define IOCTL_MIDI_BASE     0x0080
-
-// Wave device driver IOCTLs
-
-#define IOCTL_WAVE_QUERY_FORMAT         CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_WAVE_SET_FORMAT           CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_GET_CAPABILITIES     CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_WAVE_SET_STATE            CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0004, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_GET_STATE            CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0005, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_GET_POSITION         CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_SET_VOLUME           CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_WAVE_GET_VOLUME           CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_WAVE_SET_PITCH            CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_GET_PITCH            CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000A, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_SET_PLAYBACK_RATE    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000B, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_GET_PLAYBACK_RATE    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000C, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_PLAY                 CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000D, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_RECORD               CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000E, METHOD_OUT_DIRECT, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_BREAK_LOOP           CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000F, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_SET_LOW_PRIORITY     CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0010, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-
-// MIDI device driver IOCTLs
-
-#define IOCTL_MIDI_GET_CAPABILITIES   CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_MIDI_SET_STATE          CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_MIDI_GET_STATE          CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0003, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_MIDI_SET_VOLUME         CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_MIDI_GET_VOLUME         CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_MIDI_PLAY               CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_MIDI_RECORD             CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0007, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_MIDI_CACHE_PATCHES      CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0008, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_MIDI_CACHE_DRUM_PATCHES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-*/
-
-
-CRITICAL_SECTION CS;  // Serialize access to device lists
-
-HANDLE Heap;
-
- enum {
-      InvalidDevice,
-      WaveInDevice,
-      WaveOutDevice,
-      MidiInDevice,
-      MidiOutDevice,
-      AuxDevice
-};
-
-MMRESULT OpenDevice(UINT DeviceType, DWORD ID, PHANDLE pDeviceHandle,
-                    DWORD Access);
-
-MMRESULT FindDevices();
-
-DWORD GetDeviceCount(UINT DeviceType);
-
-DWORD TranslateStatus(void);
+#define DPRINT printf
+
+
+/* Need to check these */
+#define MAX_DEVICES             256
+#define MAX_DEVICE_NAME_LENGTH  256
+#define MAX_BUFFER_SIZE         1048576
+#define MAX_WAVE_BYTES          1048576
+
+/* Custom flag set when overlapped I/O is done */
+#define WHDR_COMPLETE 0x80000000
+
+
+/*
+    The kinds of devices which MMSYSTEM/WINMM may request from us.
+*/
+
+typedef enum
+{
+    WaveOutDevice,
+    WaveInDevice,
+    MidiOutDevice,
+    MidiInDevice,
+    AuxDevice
+} DeviceType;
+
+#define IsWaveDevice(devicetype) \
+    ( ( devicetype == WaveOutDevice ) || ( devicetype == WaveInDevice ) )
+
+#define IsMidiDevice(devicetype) \
+    ( ( devicetype == MidiOutDevice ) || ( devicetype == MidiInDevice ) )
+
+#define IsAuxDevice(devicetype) \
+    ( devicetype == AuxDevice )
+
+
+/*
+    We use these structures to store information regarding open devices. Since
+    the main structure gets destroyed when a device is closed, I call this a
+    "session".
+*/
+
+typedef struct
+{
+    OVERLAPPED overlap;
+    LPWAVEHDR header;
+} WaveOverlapInfo;
+
+/*
+typedef enum
+{
+    WaveAddBuffer,
+    WaveClose,
+    WaveReset,
+    WaveRestart,
+    SessionThreadTerminate,
+    InvalidFunction
+} ThreadFunction;
+*/
+
+/* Our own values, used with the session threads */
+typedef DWORD ThreadFunction;
+#define DRVM_TERMINATE   0xFFFFFFFE
+#define DRVM_INVALID     0xFFFFFFFF
+
+typedef enum
+{
+    WavePlaying,
+    WaveStopped,
+    WaveReset,
+    WaveRestart
+} WaveState;
+
+typedef union
+{
+    PWAVEHDR wave_header;
+    PMIDIHDR midi_header;
+} MediaHeader;
+
+/*
+typedef union
+{
+    MediaHeader header;
+} ThreadParameter;
+*/
+
+typedef struct _ThreadInfo
+{
+    HANDLE handle;
+    HANDLE ready_event;
+    HANDLE go_event;
+
+    /*ThreadFunction function;*/
+    DWORD function;
+    PVOID parameter;
+
+    MMRESULT result;
+} ThreadInfo;
+
+typedef struct _LoopInfo
+{
+    PWAVEHDR head;
+    DWORD iterations;
+} LoopInfo;
+
+typedef struct _SessionInfo
+{
+    struct _SessionInfo* next;
+
+    DeviceType device_type;
+    DWORD device_id;
+
+    HANDLE kernel_device_handle;
+
+    /* These are all the same */
+    union
+    {
+        HDRVR mme_handle;
+        HWAVE mme_wave_handle;
+        HMIDI mme_midi_handle;
+    };
+
+    /* If playback is paused or not */
+    BOOL is_paused;
+
+    /* Stuff passed to us from winmm */
+    DWORD app_user_data;
+    DWORD callback;
+
+    DWORD flags;
+
+    /* Can only be one or the other */
+    union
+    {
+        PWAVEHDR wave_queue;
+        PMIDIHDR midi_queue;
+    };
+
+    /* Current playback point */
+    //PWAVEHDR next_buffer;
+
+    /* Where in the current buffer we are */
+    DWORD buffer_position;
+
+//    DWORD remaining_bytes;
+
+    LoopInfo loop;
+
+    ThreadInfo thread;
+} SessionInfo;
+
+#undef ASSERT
+#define ASSERT(condition) \
+    if ( ! (condition) ) \
+        DPRINT("ASSERT FAILED: %s\n", #condition);
+
+/*
+    MME interface
+*/
+
+BOOL
+NotifyClient(
+    SessionInfo* session_info,
+    DWORD message,
+    DWORD parameter1,
+    DWORD parameter2);
+
+
+/*
+    Helpers
+*/
+
+MMRESULT
+ErrorToMmResult(UINT error_code);
+
+
+/* Kernel interface */
+
+MMRESULT
+CobbleDeviceName(
+    DeviceType device_type,
+    DWORD device_id,
+    PWCHAR out_device_name);
+
+MMRESULT
+OpenKernelDevice(
+    DeviceType device_type,
+    DWORD device_id,
+    DWORD access,
+    HANDLE* handle);
+
+VOID
+CloseKernelDevice(HANDLE device_handle);
+
+MMRESULT
+SetDeviceData(
+    HANDLE device_handle,
+    DWORD ioctl,
+    PBYTE input_buffer,
+    DWORD buffer_size);
+
+MMRESULT
+GetDeviceData(
+    HANDLE device_handle,
+    DWORD ioctl,
+    PBYTE output_buffer,
+    DWORD buffer_size);
+
+
+/* Session management */
+
+MMRESULT
+CreateSession(
+    DeviceType device_type,
+    DWORD device_id,
+    SessionInfo** session_info);
+
+VOID
+DestroySession(SessionInfo* session);
+
+SessionInfo*
+GetSession(
+    DeviceType device_type,
+    DWORD device_id);
+
+MMRESULT
+StartSessionThread(SessionInfo* session_info);
+
+MMRESULT
+CallSessionThread(
+    SessionInfo* session_info,
+    ThreadFunction function,
+    PVOID thread_parameter);
+
+DWORD
+HandleBySessionThread(
+    DWORD private_handle,
+    DWORD message,
+    DWORD parameter);
+
+
+/* General */
+
+DWORD
+GetDeviceCount(DeviceType device_type);
+
+DWORD
+GetDeviceCapabilities(
+    DeviceType device_type,
+    DWORD device_id,
+    PVOID capabilities,
+    DWORD capabilities_size);
+
+DWORD
+OpenDevice(
+    DeviceType device_type,
+    DWORD device_id,
+    PVOID open_descriptor,
+    DWORD flags,
+    DWORD private_handle);
+
+DWORD
+CloseDevice(
+    DWORD private_handle);
+
+DWORD
+PauseDevice(
+    DWORD private_handle);
+
+DWORD
+RestartDevice(
+    DWORD private_handle);
+
+DWORD
+ResetDevice(
+    DWORD private_handle);
+
+DWORD
+GetPosition(
+    DWORD private_handle,
+    PMMTIME time,
+    DWORD time_size);
+
+DWORD
+BreakLoop(DWORD private_handle);
+
+DWORD
+QueryWaveFormat(
+    DeviceType device_type,
+    PVOID lpFormat);
+
+DWORD
+WriteWaveBuffer(
+    DWORD private_handle,
+    PWAVEHDR wave_header,
+    DWORD wave_header_size);
+
+
+
+
+
+/* wave thread */
+
+DWORD
+WaveThread(LPVOID parameter);
+
+
+/* Wave I/O */
+
+VOID
+PerformWaveIO(SessionInfo* session_info);
+
+
+CRITICAL_SECTION critical_section;
+
 
 
 #endif

Modified: trunk/reactos/dll/win32/mmdrv/mmdrv.rbuild
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/mmdrv.rbuild?rev=27384&r1=27383&r2=27384&view=diff
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/mmdrv.rbuild (original)
+++ trunk/reactos/dll/win32/mmdrv/mmdrv.rbuild Wed Jul  4 14:17:48 2007
@@ -8,9 +8,11 @@
 	<library>kernel32</library>
 	<library>user32</library>
 	<library>winmm</library>
-	<file>auxil.c</file>
 	<file>entry.c</file>
-	<file>midi.c</file>
-	<file>utils.c</file>
+	<file>mme.c</file>
+	<file>kernel.c</file>
+	<file>session.c</file>
+	<file>common.c</file>
 	<file>wave.c</file>
+	<file>wave_io.c</file>
 </module>

Added: trunk/reactos/dll/win32/mmdrv/mme.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/mme.c?rev=27384&view=auto
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/mme.c (added)
+++ trunk/reactos/dll/win32/mmdrv/mme.c Wed Jul  4 14:17:48 2007
@@ -1,0 +1,143 @@
+/*
+ *
+ * COPYRIGHT:            See COPYING in the top level directory
+ * PROJECT:              ReactOS Multimedia
+ * FILE:                 dll/win32/mmdrv/mme.c
+ * PURPOSE:              Multimedia User Mode Driver (MME Interface)
+ * PROGRAMMER:           Andrew Greenwood
+ *                       Aleksey Bragin
+ * UPDATE HISTORY:
+ *                       Jan 14, 2007: Rewritten and tidied up
+ */
+
+#include <mmdrv.h>
+
+/*
+    Sends a message to the client (application), such as WOM_DONE. This
+    is just a wrapper around DriverCallback which translates the
+    parameters appropriately.
+*/
+
+BOOL
+NotifyClient(
+    SessionInfo* session_info,
+    DWORD message,
+    DWORD parameter1,
+    DWORD parameter2)
+{
+    return DriverCallback(session_info->callback,
+                          HIWORD(session_info->flags),
+                          session_info->mme_handle,
+                          message,
+                          session_info->app_user_data,
+                          parameter1,
+                          parameter2);
+}
+
+
+
+/*
+    MME Driver Entrypoint
+    Wave Output
+*/
+
+APIENTRY DWORD
+wodMessage(
+    DWORD device_id,
+    DWORD message,
+    DWORD private_handle,
+    DWORD parameter1,
+    DWORD parameter2)
+{
+    switch ( message )
+    {
+        /* http://www.osronline.com/ddkx/w98ddk/mmedia_4p80.htm */
+        case WODM_GETNUMDEVS :
+            DPRINT("WODM_GETNUMDEVS\n");
+            return GetDeviceCount(WaveOutDevice);
+
+        /* http://www.osronline.com/ddkx/w98ddk/mmedia_4p6h.htm */
+        case WODM_GETDEVCAPS :
+            DPRINT("WODM_GETDEVCAPS\n");
+            return GetDeviceCapabilities(WaveOutDevice,
+                                         device_id,
+                                         (PVOID) parameter1,
+                                         parameter2);
+
+        /* http://www.osronline.com/ddkx/w98ddk/mmedia_4p85.htm */
+        case WODM_OPEN :
+        {
+            WAVEOPENDESC* open_desc = (WAVEOPENDESC*) parameter1;
+            DPRINT("WODM_OPEN\n");
+
+            if ( parameter2 && WAVE_FORMAT_QUERY )
+                return QueryWaveFormat(WaveOutDevice, open_desc->lpFormat);
+            else
+                return OpenDevice(WaveOutDevice,
+                                  device_id,
+                                  open_desc,
+                                  parameter2,
+                                  private_handle);
+        }
+
+        /* http://www.osronline.com/ddkx/w98ddk/mmedia_4p6g.htm */
+        case WODM_CLOSE :
+        {
+            DPRINT("WODM_CLOSE\n");
+            return CloseDevice(private_handle);
+        }
+
+        /* http://www.osronline.com/ddkx/w98ddk/mmedia_4p9w.htm */
+        case WODM_WRITE :
+        {
+            DPRINT("WODM_WRITE\n");
+            return WriteWaveBuffer(private_handle,
+                                   (PWAVEHDR) parameter1,
+                                   parameter2);
+        }
+
+        /* http://www.osronline.com/ddkx/w98ddk/mmedia_4p86.htm */
+        case WODM_PAUSE :
+        {
+            DPRINT("WODM_PAUSE\n");
+            return HandleBySessionThread(private_handle, message, 0);
+        }
+
+        /* http://www.osronline.com/ddkx/w98ddk/mmedia_4p89.htm */
+        case WODM_RESTART :
+        {
+            DPRINT("WODM_RESTART\n");
+            return HandleBySessionThread(private_handle, message, 0);
+        }
+
+        /* http://www.osronline.com/ddkx/w98ddk/mmedia_4p88.htm */
+        case WODM_RESET :
+        {
+            DPRINT("WODM_RESET\n");
+            return HandleBySessionThread(private_handle, message, 0);
+        }
+
+        /* http://www.osronline.com/ddkx/w98ddk/mmedia_4p83.htm */
+#if 0
+        case WODM_GETPOS :
+        {
+            DPRINT("WODM_GETPOS\n");
+            return GetPosition(private_handle,
+                               (PMMTIME) parameter1,
+                               parameter2);
+        }
+#endif
+
+        /* http://www.osronline.com/ddkx/w98ddk/mmedia_4p6f.htm */
+        case WODM_BREAKLOOP :
+        {
+            DPRINT("WODM_BREAKLOOP\n");
+            return HandleBySessionThread(private_handle, message, 0);
+        }
+
+        /* TODO: Others */
+    }
+
+    DPRINT("Unsupported message\n");
+    return MMSYSERR_NOTSUPPORTED;
+}

Added: trunk/reactos/dll/win32/mmdrv/mmioctl.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/mmioctl.h?rev=27384&view=auto
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/mmioctl.h (added)
+++ trunk/reactos/dll/win32/mmdrv/mmioctl.h Wed Jul  4 14:17:48 2007
@@ -1,0 +1,147 @@
+/*
+ *
+ * COPYRIGHT:            See COPYING in the top level directory
+ * PROJECT:              ReactOS Multimedia
+ * FILE:                 dll/win32/mmdrv/mmioctl.h
+ * PURPOSE:              Multimedia system NT4 compatibility
+ * PROGRAMMER:           Andrew Greenwood
+ * UPDATE HISTORY:
+ *                       Jan 13, 2007: Split from mmdrv.h
+ */
+
+#ifndef MMDRV_IOCTLS
+#define MMDRV_IOCTLS
+
+
+#include <windows.h>
+#include <mmsystem.h>
+#include <mmddk.h>
+#include <winioctl.h>
+
+
+/*
+    Base names of the supported devices, as provided by drivers running in
+    kernel mode.
+
+    \Device\WaveIn0 etc.
+*/
+
+#define WAVE_OUT_DEVICE_NAME    L"\\Device\\WaveOut"
+#define WAVE_IN_DEVICE_NAME     L"\\Device\\WaveIn"
+#define MIDI_OUT_DEVICE_NAME    L"\\Device\\MidiOut"
+#define MIDI_IN_DEVICE_NAME     L"\\Device\\MidiIn"
+#define AUX_DEVICE_NAME         L"\\Device\\MMAux"
+
+
+/*
+    Base IOCTL codes
+*/
+
+#define IOCTL_SOUND_BASE    FILE_DEVICE_SOUND
+#define IOCTL_WAVE_BASE     0x0000
+#define IOCTL_MIDI_BASE     0x0080
+#define IOCTL_AUX_BASE      0x0100
+
+
+/*
+    Wave IOCTLs
+*/
+
+#define IOCTL_WAVE_QUERY_FORMAT \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_WAVE_SET_FORMAT \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_GET_CAPABILITIES \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_WAVE_SET_STATE \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0004, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_GET_STATE \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0005, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_GET_POSITION \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_SET_VOLUME \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_WAVE_GET_VOLUME \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_WAVE_SET_PITCH \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_GET_PITCH \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000A, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_SET_PLAYBACK_RATE \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000B, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_GET_PLAYBACK_RATE \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000C, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_PLAY \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000D, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_RECORD \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000E, METHOD_OUT_DIRECT, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_BREAK_LOOP \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000F, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_SET_LOW_PRIORITY \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0010, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+
+/*
+    MIDI IOCTLs
+*/
+
+#define IOCTL_MIDI_GET_CAPABILITIES \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_MIDI_SET_STATE \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_MIDI_GET_STATE \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0003, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_MIDI_SET_VOLUME \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_MIDI_GET_VOLUME \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_MIDI_PLAY \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_MIDI_RECORD \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0007, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_MIDI_CACHE_PATCHES \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0008, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+#define IOCTL_MIDI_CACHE_DRUM_PATCHES \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+
+/*
+    Aux IOCTLs
+*/
+
+#define IOCTL_AUX_GET_CAPABILITIES \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_AUX_SET_VOLUME \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_AUX_GET_VOLUME \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_SOUND_GET_CHANGED_VOLUME \
+    CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#endif

Added: trunk/reactos/dll/win32/mmdrv/session.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/session.c?rev=27384&view=auto
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/session.c (added)
+++ trunk/reactos/dll/win32/mmdrv/session.c Wed Jul  4 14:17:48 2007
@@ -1,0 +1,245 @@
+/*
+ *
+ * COPYRIGHT:            See COPYING in the top level directory
+ * PROJECT:              ReactOS Multimedia
+ * FILE:                 dll/win32/mmdrv/session.c
+ * PURPOSE:              Multimedia User Mode Driver (session management)
+ * PROGRAMMER:           Andrew Greenwood
+ * UPDATE HISTORY:
+ *                       Jan 14, 2007: Created
+ */
+
+#include <mmdrv.h>
+
+/* Each session is tracked, but the list must be locked when in use  */
+
+SessionInfo* session_list = NULL;
+CRITICAL_SECTION session_lock;
+
+
+/*
+    Obtains a pointer to the session associated with a device type and ID.
+    If no session exists, returns NULL. This is mainly used to see if a
+    session already exists prior to creating a new one.
+*/
+
+SessionInfo*
+GetSession(
+    DeviceType device_type,
+    DWORD device_id)
+{
+    SessionInfo* session_info;
+
+    EnterCriticalSection(&session_lock);
+    session_info = session_list;
+
+    while ( session_info )
+    {
+        if ( ( session_info->device_type == device_type ) &&
+             ( session_info->device_id == device_id ) )
+        {
+            LeaveCriticalSection(&session_lock);
+            return session_info;
+        }
+
+        session_info = session_info->next;
+    }
+
+    LeaveCriticalSection(&session_lock);
+    return NULL;
+}
+
+
+/*
+    Creates a new session, associated with the specified device type and ID.
+    Whilst the session list is locked, this also checks to see if an existing
+    session is associated with the device.
+*/
+
+MMRESULT
+CreateSession(
+    DeviceType device_type,
+    DWORD device_id,
+    SessionInfo** session_info)
+{
+    HANDLE heap = GetProcessHeap();
+
+    ASSERT(session_info);
+
+    EnterCriticalSection(&session_lock);
+
+    /* Ensure we're not creating a duplicate session */
+
+    if ( GetSession(device_type, device_id) )
+    {
+        DPRINT("Already allocated session\n");
+        LeaveCriticalSection(&session_lock);
+        return MMSYSERR_ALLOCATED;
+    }
+
+    *session_info = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(SessionInfo));
+
+    if ( ! *session_info )
+    {
+        DPRINT("Failed to allocate mem for session info\n");
+        LeaveCriticalSection(&session_lock);
+        return MMSYSERR_NOMEM;
+    }
+
+    (*session_info)->device_type = device_type;
+    (*session_info)->device_id = device_id;
+
+    /* Add to the list */
+
+    (*session_info)->next = session_list;
+    session_list = *session_info;
+
+    LeaveCriticalSection(&session_lock);
+
+    return MMSYSERR_NOERROR;
+}
+
+
+/*
+    Removes a session from the list and destroys it. This function does NOT
+    perform any additional cleanup. Think of it as a slightly more advanced
+    free()
+*/
+
+VOID
+DestroySession(SessionInfo* session)
+{
+    HANDLE heap = GetProcessHeap();
+    SessionInfo* session_node;
+    SessionInfo* session_prev;
+
+    /* TODO: More cleanup stuff */
+
+    /* Remove from the list */
+
+    EnterCriticalSection(&session_lock);
+
+    session_node = session_list;
+    session_prev = NULL;
+
+    while ( session_node )
+    {
+        if ( session_node == session )
+        {
+            /* Bridge the gap for when we go */
+            session_prev->next = session->next;
+            break;
+        }
+
+        /* Save the previous node, fetch the next */
+        session_prev = session_node;
+        session_node = session_node->next;
+    }
+
+    LeaveCriticalSection(&session_lock);
+
+    HeapFree(heap, 0, session);
+}
+
+
+/*
+    Allocates events and other resources for the session thread, starts it,
+    and waits for it to announce that it is ready to work for us.
+*/
+
+MMRESULT
+StartSessionThread(SessionInfo* session_info)
+{
+    LPTASKCALLBACK task;
+    MMRESULT result;
+
+    ASSERT(session_info);
+
+    /* This is our "ready" event, sent when the thread is idle */
+
+    session_info->thread.ready_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+    if ( ! session_info->thread.ready_event )
+    {
+        DPRINT("Couldn't create thread_ready event\n");
+        return MMSYSERR_NOMEM;
+    }
+
+    /* This is our "go" event, sent when we want the thread to do something */
+
+    session_info->thread.go_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+    if ( ! session_info->thread.go_event )
+    {
+        DPRINT("Couldn't create thread_go event\n");
+        CloseHandle(session_info->thread.ready_event);
+        return MMSYSERR_NOMEM;
+    }
+
+    /* TODO - other kinds of devices need attention, too */
+    task = ( session_info->device_type == WaveOutDevice )
+           ? (LPTASKCALLBACK) WaveThread : NULL;
+
+    ASSERT(task);
+
+    /* Effectively, this is a beefed-up CreateThread */
+
+    result = mmTaskCreate(task,
+                          &session_info->thread.handle,
+                          (DWORD) session_info);
+
+    if ( result != MMSYSERR_NOERROR )
+    {
+        DPRINT("Task creation failed\n");
+        CloseHandle(session_info->thread.ready_event);
+        CloseHandle(session_info->thread.go_event);
+        return result;
+    }
+
+    /* Wait for the thread to be ready before completing */
+
+    WaitForSingleObject(session_info->thread.ready_event, INFINITE);
+
+    return MMSYSERR_NOERROR;
+}
+
+
+/*
+    The session thread is pretty simple. Upon creation, it announces that it
+    is ready to do stuff for us. When we want it to perform an action, we use
+    CallSessionThread with an appropriate function and parameter, then tell
+    the thread we want it to do something. When it's finished, it announces
+    that it is ready once again.
+*/
+
+MMRESULT
+CallSessionThread(
+    SessionInfo* session_info,
+    ThreadFunction function,
+    PVOID thread_parameter)
+{
+    ASSERT(session_info);
+
+    session_info->thread.function = function;
+    session_info->thread.parameter = thread_parameter;
+
+    DPRINT("Calling session thread\n");
+    SetEvent(session_info->thread.go_event);
+
+    DPRINT("Waiting for thread response\n");
+    WaitForSingleObject(session_info->thread.ready_event, INFINITE);
+
+    return session_info->thread.result;
+}
+
+
+DWORD
+HandleBySessionThread(
+    DWORD private_handle,
+    DWORD message,
+    DWORD parameter)
+{
+    return CallSessionThread((SessionInfo*) private_handle,
+                             message,
+                             (PVOID) parameter);
+}

Modified: trunk/reactos/dll/win32/mmdrv/wave.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/wave.c?rev=27384&r1=27383&r2=27384&view=diff
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/wave.c (original)
+++ trunk/reactos/dll/win32/mmdrv/wave.c Wed Jul  4 14:17:48 2007
@@ -2,1047 +2,380 @@
  *
  * COPYRIGHT:            See COPYING in the top level directory
  * PROJECT:              ReactOS Multimedia
- * FILE:                 lib/mmdrv/wave.c
- * PURPOSE:              Multimedia User Mode Driver
+ * FILE:                 dll/win32/mmdrv/wave.c
+ * PURPOSE:              Multimedia User Mode Driver (Wave Audio)
  * PROGRAMMER:           Andrew Greenwood
- *                       Aleksey Bragin (aleksey at studiocerebral.com)
  * UPDATE HISTORY:
- *                       Jan 30, 2004: Imported into ReactOS tree (Greenwood)
- *                       Mar 16, 2004: Implemented some funcs (Bragin)
+ *                       Jan 30, 2004: Imported into ReactOS tree
+ *                       Jan 14, 2007: Rewritten and tidied up
  */
 
-#include "mmdrv.h"
-#include "wave.h"
-
-#define NDEBUG
-#include <debug.h>
-
-#define WHDR_COMPLETE 0x80000000
-#define MAX_BUFFER_SIZE           8192  
-#define MAX_WAVE_BYTES          5*MAX_BUFFER_SIZE  
-
-PWAVEALLOC WaveLists; 
-
-static MMRESULT waveReadWrite(PWAVEALLOC pClient);
-void wavePartialOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
-void waveOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
-void waveLoopOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
-void waveBreakOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
-static MMRESULT waveSetState(PWAVEALLOC pClient, ULONG State);
-
-/* ============================
- *  INTERNAL
- *  functions start here
- * ============================
- */
-
-MMRESULT GetDeviceCapabilities(DWORD ID, UINT DeviceType,
-                                      LPBYTE pCaps, DWORD Size)
-{
-    HANDLE DeviceHandle = NULL;
-    MMRESULT Result = MMSYSERR_NOERROR;
-    DWORD BytesReturned = 0;
-
-    // Open the wave device
-
-    Result = OpenDevice(DeviceType, ID, &DeviceHandle, GENERIC_READ);
-    if (Result != MMSYSERR_NOERROR)
-         return Result;
-
-	if ((DeviceType == WaveOutDevice) || (DeviceType == WaveInDevice))
-	{
-		Result = DeviceIoControl(DeviceHandle, IOCTL_WAVE_GET_CAPABILITIES,
-                            NULL, 0, (LPVOID)pCaps, Size,
-                  &BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
-	}
-
-	else if ((DeviceType == MidiInDevice) || (DeviceType == MidiOutDevice))
-	{
-	    Result = DeviceIoControl(DeviceHandle, IOCTL_MIDI_GET_CAPABILITIES,
-                            NULL, 0, (LPVOID)pCaps, Size,
-                  &BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
-	}
-
-    else if (DeviceType == AuxDevice)
-	{
-	    Result = DeviceIoControl(DeviceHandle, IOCTL_AUX_GET_CAPABILITIES,
-                            NULL, 0, (LPVOID)pCaps, Size,
-                  &BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
-	}
-
-    // Close the handle and return the result code
-    CloseHandle(DeviceHandle);
-
-    return Result;
-}
-
-static DWORD waveThread(LPVOID lpParameter)
-{
-
-    PWAVEALLOC pClient = (PWAVEALLOC)lpParameter;
-    BOOL Terminate = FALSE;
-
+#include <mmdrv.h>
+
+
+#define MAX_WAVE_BUFFER_SIZE    65536
+
+
+MMRESULT
+QueueWaveBuffer(
+    SessionInfo* session_info,
+    LPWAVEHDR wave_header)
+{
+    PWAVEHDR queue_node, previous_node;
+    DPRINT("Queueing wave buffer\n");
+
+    if ( ! wave_header )
+    {
+        return MMSYSERR_INVALPARAM;
+    }
+
+    if ( ! wave_header->lpData )
+    {
+        return MMSYSERR_INVALPARAM;
+    }
+
+    /* Headers must be prepared first */
+    if ( ! ( wave_header->dwFlags & WHDR_PREPARED ) )
+    {
+        DPRINT("I was given a header which hasn't been prepared yet!\n");
+        return WAVERR_UNPREPARED;
+    }
+
+    /* ...and they must not already be in the playing queue! */
+    if ( wave_header->dwFlags & WHDR_INQUEUE )
+    {
+        DPRINT("I was given a header for a buffer which is already playing\n");
+        return WAVERR_STILLPLAYING;
+    }
+
+    /* Initialize */
+    wave_header->dwBytesRecorded = 0;
+
+    /* Clear the DONE bit, and mark the buffer as queued */
+    wave_header->dwFlags &= ~WHDR_DONE;
+    wave_header->dwFlags |= WHDR_INQUEUE;
+
+    /* Save our handle in the header */
+    wave_header->reserved = (DWORD) session_info;
+
+    /* Locate the end of the queue */
+    previous_node = NULL;
+    queue_node = session_info->wave_queue;
+
+    while ( queue_node )
+    {
+        previous_node = queue_node;
+        queue_node = queue_node->lpNext;
+    }
+
+    /* Go back a step to obtain the previous node (non-NULL) */
+    queue_node = previous_node;
+
+    /* Append our buffer here, and terminate the queue */
+    queue_node->lpNext = wave_header;
+    wave_header->lpNext = NULL;
+
+    /* When no buffers are playing there's no play queue so we start one */
+#if 0
+    if ( ! session_info->next_buffer )
+    {
+        session_info->buffer_position = 0;
+        session_info->next_buffer = wave_header;
+    }
+#endif
+
+    /* Pass to the driver - happens automatically during playback */
+//    return PerformWaveIO(session_info);
+    return MMSYSERR_NOERROR;
+}
+
+VOID
+ReturnCompletedBuffers(SessionInfo* session_info)
+{
+    PWAVEHDR header = NULL;
+
+    /* Set the current header and test to ensure it's not NULL */
+    while ( ( header = session_info->wave_queue ) )
+    {
+        if ( header->dwFlags & WHDR_DONE )
+        {
+            DWORD message;
+
+            /* Mark as done, and unqueued */
+            header->dwFlags &= ~WHDR_INQUEUE;
+            header->dwFlags |= WHDR_DONE;
+
+            /* Trim it from the start of the queue */
+            session_info->wave_queue = header->lpNext;
+
+            /* Choose appropriate notification */
+            message = (session_info->device_type == WaveOutDevice) ? WOM_DONE :
+                                                                     WIM_DATA;
+
+            DPRINT("Notifying client that buffer 0x%x is done\n", (int) header);
+
+            /* Notify the client */
+            NotifyClient(session_info, message, (DWORD) header, 0);
+        }
+    }
+
+    /* TODO: Perform I/O as a new buffer may have arrived */
+}
+
+
+/*
+    Each thread function/request is packed into the SessionInfo structure
+    using a function ID and a parameter (in some cases.) When the function
+    completes, the function code is set to an "invalid" value. This is,
+    effectively, a hub for operations where sound driver I/O is concerned.
+    It handles MME message codes so is a form of deferred wodMessage().
+*/
+
+DWORD
+ProcessSessionThreadRequest(SessionInfo* session_info)
+{
+    MMRESULT result = MMSYSERR_NOERROR;
+
+    switch ( session_info->thread.function )
+    {
+        case WODM_WRITE :
+        {
+            result = QueueWaveBuffer(session_info,
+                                     (LPWAVEHDR) session_info->thread.parameter);
+            break;
+        }
+
+        case WODM_RESET :
+        {
+            /* TODO */
+            break;
+        }
+
+        case WODM_PAUSE :
+        {
+            /* TODO */
+            break;
+        }
+
+        case WODM_RESTART :
+        {
+            /* TODO */
+            break;
+        }
+
+        case WODM_GETPOS :
+        {
+            /* TODO */
+            break;
+        }
+
+        case WODM_SETPITCH :
+        {
+            result = SetDeviceData(session_info->kernel_device_handle,
+                                   IOCTL_WAVE_SET_PITCH,
+                                   (PBYTE) session_info->thread.parameter,
+                                   sizeof(DWORD));
+            break;
+        }
+
+        case WODM_GETPITCH :
+        {
+            result = GetDeviceData(session_info->kernel_device_handle,
+                                   IOCTL_WAVE_GET_PITCH,
+                                   (PBYTE) session_info->thread.parameter,
+                                   sizeof(DWORD));
+            break;
+        }
+
+        case WODM_SETVOLUME :
+        {
+            break;
+        }
+
+        case WODM_GETVOLUME :
+        {
+#if 0
+            result = GetDeviceData(session_info->kernel_device_handle,
+                                   IOCTL_WAVE_GET_VOLUME,
+                                   (PBYTE) session_info->thread.parameter,);
+#endif
+            break;
+        }
+
+        case WODM_SETPLAYBACKRATE :
+        {
+            result = SetDeviceData(session_info->kernel_device_handle,
+                                   IOCTL_WAVE_SET_PLAYBACK_RATE,
+                                   (PBYTE) session_info->thread.parameter,
+                                   sizeof(DWORD));
+            break;
+        }
+
+        case WODM_GETPLAYBACKRATE :
+        {
+            result = GetDeviceData(session_info->kernel_device_handle,
+                                   IOCTL_WAVE_GET_PLAYBACK_RATE,
+                                   (PBYTE) session_info->thread.parameter,
+                                   sizeof(DWORD));
+            break;
+        }
+
+        case WODM_CLOSE :
+        {
+            DPRINT("Thread was asked if OK to close device\n");
+
+            if ( session_info->wave_queue != NULL )
+                result = WAVERR_STILLPLAYING;
+            else
+                result = MMSYSERR_NOERROR;
+
+            break;
+        }
+
+        case DRVM_TERMINATE :
+        {
+            DPRINT("Terminating thread...\n");
+            result = MMSYSERR_NOERROR;
+            break;
+        }
+
+        default :
+        {
+            DPRINT("INVALID FUNCTION\n");
+            result = MMSYSERR_ERROR;
+            break;
+        }
+    }
+
+    /* We're done with the function now */
+
+    return result;
+}
+
+
+/*
+    The wave "session". This starts, sets itself as high priority, then waits
+    for the "go" event. When this occurs, it processes the requested function,
+    tidies up any buffers that have finished playing, sends new buffers to the
+    sound driver, then continues handing finished buffers back to the calling
+    application until it's asked to do something else.
+*/
+
+DWORD
+WaveThread(LPVOID parameter)
+{
+    MMRESULT result = MMSYSERR_ERROR;
+    SessionInfo* session_info = (SessionInfo*) parameter;
+    BOOL terminate = FALSE;
+
+    /* All your CPU time are belong to us */
     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
-    SetEvent(pClient->AuxEvent2);
-    WaitForSingleObject(pClient->AuxEvent1, INFINITE);
-
-    for (;;) 
-    {
-        switch (pClient->AuxFunction) 
-        {
-            case WaveThreadAddBuffer:
-                {
-                 LPWAVEHDR *pHdrSearching;
-
-                 if (pClient->DeviceType == WaveInDevice)             
-                     pClient->AuxParam.pHdr->dwBytesRecorded = 0;
-            
-                 pHdrSearching = &pClient->DeviceQueue;
-                 pClient->AuxParam.pHdr->lpNext = NULL;
-                 
-                 while (*pHdrSearching) 
-                 {
-                    pHdrSearching = &(*pHdrSearching)->lpNext;
-                 }
-                   
-                 if (pClient->NextBuffer == NULL) 
-                 {
-                     pClient->BufferPosition = 0;
-                     pClient->NextBuffer = pClient->AuxParam.pHdr;
-                        
-                 }
-
-                 *pHdrSearching = pClient->AuxParam.pHdr;
-
-                 pClient->AuxReturnCode = waveReadWrite(pClient);
-                }
-                 break;
-                 
-            case WaveThreadSetState:
-                 pClient->AuxReturnCode = waveSetState(pClient, pClient->AuxParam.State);
-
-                 if (pClient->AuxParam.State == WAVE_DD_RESET) 
-                 {
-                    PWAVEHDR pHdr;
-              
-                    pClient->LoopHead = NULL;
-                    pClient->AuxReturnCode = MMSYSERR_NOERROR;                               
-                    for (pHdr = pClient->DeviceQueue; pHdr != NULL; pHdr = pHdr->lpNext) 
-                    {
-                        pHdr->dwFlags |= WHDR_COMPLETE;
-                    }
-        
-                    pClient->BufferPosition = 0;
-                    pClient->NextBuffer = NULL;                    
-                } 
-                else 
-                {
-                    if (pClient->DeviceType == WaveInDevice && pClient->AuxReturnCode == MMSYSERR_NOERROR) 
-                    {
-                        if (pClient->AuxParam.State == WAVE_DD_STOP) 
-                        {                        
-                            if (pClient->DeviceQueue) 
-                            {
-                                while (!(pClient->DeviceQueue->dwFlags & WHDR_COMPLETE) &&
-                                        pClient->BytesOutstanding != 0) 
-                                {
-                                    waveSetState(pClient, WAVE_DD_RECORD);
-                                    pClient->AuxReturnCode = waveSetState(pClient, WAVE_DD_STOP);
-                                    if (pClient->AuxReturnCode != MMSYSERR_NOERROR)                                     
-                                        break;
-                                    
-                                }
-                                if (pClient->AuxReturnCode == MMSYSERR_NOERROR) 
-                                {
-                                    pClient->DeviceQueue->dwFlags |= WHDR_COMPLETE;
-                                    if (pClient->NextBuffer == pClient->DeviceQueue) 
-                                    {
-                                        pClient->NextBuffer = pClient->DeviceQueue->lpNext;
-                                        pClient->BufferPosition = 0;
-                                    }
-                                }
-                            }
-                      } 
-                      else 
-                      {                      
-                        if (pClient->AuxParam.State == WAVE_DD_RECORD) 
-                                pClient->AuxReturnCode = waveReadWrite(pClient);                        
-                      }
-                    }
-                 }
-
-                 break;
-
-            case WaveThreadGetData:                 
-                 {
-                    OVERLAPPED Overlap;
-                    DWORD BytesReturned;
-
-                    // FIXME
-                    // Assert(hDev != NULL);
-
-                    memset(&Overlap, 0, sizeof(Overlap));
-
-                    Overlap.hEvent = pClient->Event;
-
-                    if (!DeviceIoControl(pClient->hDev, pClient->AuxParam.GetSetData.Function, NULL, 0,
-                         pClient->AuxParam.GetSetData.pData, pClient->AuxParam.GetSetData.DataLen,
-                         &BytesReturned, &Overlap)) 
-                    {
-                        DWORD cbTransfer;
-
-                        if (GetLastError() != ERROR_IO_PENDING) 
-                            pClient->AuxReturnCode = TranslateStatus();
-                        else
-                        {
-
-                            if (!GetOverlappedResult(pClient->hDev, &Overlap, &cbTransfer, TRUE))                         
-                                pClient->AuxReturnCode = TranslateStatus();                        
-                        } 
-                    }
-                    else
-                    {
-                        while (SetEvent(pClient->Event) && WaitForSingleObjectEx(pClient->Event, 0, TRUE) == 
-                            WAIT_IO_COMPLETION) {}
-
-                        pClient->AuxReturnCode = MMSYSERR_NOERROR;
-                    }
-                 }
-                 break;
-
-            case WaveThreadSetData:
-                 {
-                    OVERLAPPED Overlap;
-                    DWORD BytesReturned;
-                    memset((PVOID)&Overlap, 0, sizeof(Overlap));
-                    Overlap.hEvent = pClient->Event;
-    
-                    if (!DeviceIoControl(pClient->hDev, pClient->AuxParam.GetSetData.Function, 
-                                      pClient->AuxParam.GetSetData.pData, pClient->AuxParam.GetSetData.DataLen, 
-                                      NULL, 0, &BytesReturned, &Overlap)) 
-                    {
-                        DWORD cbTransfer;
-                        if (GetLastError() == ERROR_IO_PENDING) 
-                        {
-                            if (!GetOverlappedResult(pClient->hDev, &Overlap, &cbTransfer, TRUE))             
-                                pClient->AuxReturnCode = TranslateStatus();             
-                        } 
-                        else              
-                            pClient->AuxReturnCode = TranslateStatus();
-         
-                    }
-                    else
-                    { 
-                        while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION) {}
-
-                        pClient->AuxReturnCode = MMSYSERR_NOERROR;
-                    }
-                 }                
-                 break;
-
-            case WaveThreadBreakLoop:
-                 pClient->AuxReturnCode = MMSYSERR_NOERROR;
-                 if (pClient->LoopHead)                 
-                    pClient->LoopCount = 0;                          
-                 break;
-
-            case WaveThreadClose:
-                 if (pClient->DeviceQueue != NULL)                  
-                    pClient->AuxReturnCode = WAVERR_STILLPLAYING;                 
-                 else                 
-                    pClient->AuxReturnCode = MMSYSERR_NOERROR;                
-                 break;
-
-            case WaveThreadTerminate:
-                 Terminate = TRUE;
-                 break;
-
-            default:
-                 DPRINT("WaveThread Error");
-                 break;
-
-        }
-
-        pClient->AuxFunction = WaveThreadInvalid;
-
-        while (pClient->DeviceQueue && (pClient->DeviceQueue->dwFlags & WHDR_COMPLETE)) 
-        {
-            PWAVEHDR pHdr;        
-            PWAVEALLOC pWav;
-
-            pHdr = pClient->DeviceQueue;        
-            pClient->DeviceQueue = pHdr->lpNext;
-    
-            pHdr->dwFlags &= ~WHDR_COMPLETE;
-            pHdr->dwFlags &= ~WHDR_INQUEUE;
-            pHdr->lpNext = NULL;
-            pHdr->dwFlags |= WHDR_DONE;
-
-            pWav = (PWAVEALLOC)pHdr->reserved;
-                
-            if (pWav->dwCallback)
-            {
-                DriverCallback(pWav->dwCallback, HIWORD(pWav->dwFlags), (HDRVR)pWav->hWave,  
-                           pClient->DeviceType == WaveOutDevice ? WOM_DONE : WIM_DATA, 
-                           pWav->dwInstance, (DWORD)pHdr, 0L); 
-            }
-        }
-
-        waveReadWrite(pClient);
-
-        if (Terminate) return 1; 
-        SetEvent(pClient->AuxEvent2);
-        while (WaitForSingleObjectEx(pClient->AuxEvent1, INFINITE, TRUE) == WAIT_IO_COMPLETION) 
-        {
-           while (pClient->DeviceQueue && (pClient->DeviceQueue->dwFlags & WHDR_COMPLETE)) 
-           {
-                PWAVEHDR pHdr;        
-                PWAVEALLOC pWav;
-
-                pHdr = pClient->DeviceQueue;        
-                pClient->DeviceQueue = pHdr->lpNext;
-    
-                pHdr->dwFlags &= ~WHDR_COMPLETE;
-                pHdr->dwFlags &= ~WHDR_INQUEUE;
-                pHdr->lpNext = NULL;
-                pHdr->dwFlags |= WHDR_DONE;
-
-                pWav = (PWAVEALLOC)pHdr->reserved;
-                
-                if (pWav->dwCallback)
-                {
-                    DriverCallback(pWav->dwCallback, HIWORD(pWav->dwFlags), (HDRVR)pWav->hWave,  
-                           pClient->DeviceType == WaveOutDevice ? WOM_DONE : WIM_DATA, 
-                           pWav->dwInstance, (DWORD)pHdr, 0L); 
-                }
-            }
-
-        waveReadWrite(pClient);
-        }
-    }
-
-
-  return MMSYSERR_NOERROR;
-}
-
-
-static MMRESULT waveReadWrite(PWAVEALLOC pClient)
-{
-    DWORD dwSize;
-    BOOL Result = FALSE;
-
-   
-    while (pClient->NextBuffer) 
-    {
-        PWAVEHDR pHdr;
-
-        pHdr = pClient->NextBuffer;
-        
-        //FIXME
-        //assert(!(pHdr->dwFlags & (WHDR_DONE | WHDR_COMPLETE)));
-        //assert(pClient->DeviceQueue != NULL);
-        
-
-        dwSize = pHdr->dwBufferLength - pClient->BufferPosition;
-        if (dwSize > MAX_BUFFER_SIZE)         
-            dwSize = MAX_BUFFER_SIZE;
-        
-
-        if (dwSize + pClient->BytesOutstanding <= MAX_WAVE_BYTES) 
-        {
-            PWAVEOVL pWaveOvl;
-
-            if (pClient->BufferPosition == 0) 
-            {
-                if (pClient->NextBuffer && (pClient->NextBuffer->dwFlags & WHDR_BEGINLOOP) &&
-                    pClient->NextBuffer != pClient->LoopHead) 
-                {
-                    pClient->LoopCount = pClient->NextBuffer->dwLoops;
-                    pClient->LoopHead = pClient->NextBuffer;                    
-                    if (pClient->LoopCount > 0)                     
-                        pClient->LoopCount--;                    
-                }
-                
-                if (pClient->LoopCount == 0)                 
-                    pClient->LoopHead = NULL;                
-            }
-
-            pWaveOvl = (PWAVEOVL)HeapAlloc(Heap, HEAP_ZERO_MEMORY, sizeof(*pWaveOvl));
-
-            if (pWaveOvl == NULL) 
-                return MMSYSERR_NOMEM;
-            
-            pWaveOvl->WaveHdr = pHdr;
-
-            if (pClient->DeviceType == WaveOutDevice) 
-            {
-                Result =  WriteFileEx(pClient->hDev, 
-                                      (PBYTE)pHdr->lpData + pClient->BufferPosition, 
-                                      dwSize,
-                                     (LPOVERLAPPED)pWaveOvl,
-                                     (LPOVERLAPPED_COMPLETION_ROUTINE)
-                                      (pHdr->dwBufferLength != 
-                                      pClient->BufferPosition + dwSize ? wavePartialOvl : NULL != pClient->LoopHead ?
-                                      waveLoopOvl : waveOvl));
-            } 
-            else if (pClient->DeviceType == WaveInDevice) 
-            {
-                Result =  ReadFileEx(pClient->hDev, (PBYTE)pHdr->lpData + pClient->BufferPosition,
-                                     dwSize, (LPOVERLAPPED)pWaveOvl, 
-                                     (LPOVERLAPPED_COMPLETION_ROUTINE)
-                                     (pHdr->dwBufferLength !=
-                                     pClient->BufferPosition + dwSize ? wavePartialOvl : NULL != pClient->LoopHead ?
-                                     waveLoopOvl :  waveOvl));
-            }
-
-            
-            if (!Result && GetLastError() != ERROR_IO_PENDING) 
-            {
-               HeapFree(Heap, 0, (LPSTR)pWaveOvl);
-               
-                if (pClient->BytesOutstanding == 0) 
-                {
-                    PWAVEHDR pHdr;
-                    for (pHdr = pClient->DeviceQueue; pHdr != NULL; pHdr = pHdr->lpNext) 
-                    {
-                        pHdr->dwFlags |= WHDR_COMPLETE;
-                    }
-        
-                    pClient->NextBuffer = NULL;
-                    pClient->BufferPosition = 0;
-                    
-                }
-                return TranslateStatus();
-
-            } 
-            else 
-            {
-                pClient->BufferPosition += dwSize;
-                pClient->BytesOutstanding += dwSize;                
-                if (pClient->BufferPosition == pHdr->dwBufferLength) 
-                {
-                
-                    if (!pClient->LoopHead || !(pHdr->dwFlags & WHDR_ENDLOOP))                     
-                        pClient->NextBuffer = pHdr->lpNext;                    
-                    else 
-                    {                    
-                        if (pClient->LoopCount != 0) 
-                        {                            
-                            pClient->NextBuffer = pClient->LoopHead;
-                            pClient->LoopCount--;
-                        } 
-                        else 
-                        {
-                            pClient->DummyWaveOvl.WaveHdr = pClient->LoopHead;
-
-                            Result = WriteFileEx(pClient->hDev, (PVOID)pHdr->lpData, 0,
-                                                 &pClient->DummyWaveOvl.Ovl, 
-                                                 (LPOVERLAPPED_COMPLETION_ROUTINE)waveBreakOvl);
-
-                            if (Result || GetLastError() == ERROR_IO_PENDING) 
-                            {
-                                pClient->NextBuffer = pHdr->lpNext;
-                                pClient->LoopHead = NULL;
-                                
-                            }
-                        }
-                    }
-                    pClient->BufferPosition = 0;
-                }
-            }
-            
-
-        } 
-        else                         
-          break;        
-     }
-    return MMSYSERR_NOERROR;
-}
-static MMRESULT waveSetState(PWAVEALLOC pClient, ULONG State)
-{    
-    OVERLAPPED Overlap;
-    DWORD BytesReturned;
-
-    memset((PVOID)&Overlap, 0, sizeof(Overlap));
-
-    Overlap.hEvent = pClient->Event;
-    
-    if (!DeviceIoControl(pClient->hDev, IOCTL_WAVE_SET_STATE, 
-                         &State,  sizeof(State), NULL, 0, &BytesReturned, &Overlap)) 
-    {
-         DWORD cbTransfer;        
-         if (GetLastError() == ERROR_IO_PENDING) 
-         {
-             if (!GetOverlappedResult(pClient->hDev, &Overlap, &cbTransfer, TRUE))             
-                  return TranslateStatus();             
-         } 
-         else              
-             return TranslateStatus();
-         
-    }
-
-    while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION) {}
-    return MMSYSERR_NOERROR;
-}
-
-void wavePartialOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
-{
-    LPWAVEHDR pHdr;
-    PWAVEALLOC pClient;
-
-    pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;    
-    pClient = (PWAVEALLOC)pHdr->reserved;
-
-  
-    /* FIXME
-    Assert(pHdr->dwFlags & WHDR_INQUEUE);
-    Assert(!(pHdr->dwFlags & WHDR_COMPLETE));
-    */    
-
-    pClient->BytesOutstanding -= MAX_BUFFER_SIZE;
-
-    if (pClient->DeviceType == WaveInDevice)     
-        pHdr->dwBytesRecorded += BytesTransferred;
-    HeapFree(Heap, 0, (LPSTR)pOverlapped);
-}
-
-void waveBreakOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
-{
-    ((PWAVEOVL)pOverlapped)->WaveHdr->dwFlags |= WHDR_COMPLETE;
-}
-
-void waveLoopOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
-{
-    DWORD dwFlags;
-    PWAVEHDR pHdr;
-    
-    pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;
-    dwFlags = pHdr->dwFlags;
-    waveOvl(dwErrorCode, BytesTransferred, pOverlapped);
-    pHdr->dwFlags = dwFlags;
-}
-
-void waveOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
-{
-    PWAVEHDR pHdr;
-    PWAVEALLOC pClient;
-
-    pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;    
-    pClient = (PWAVEALLOC)pHdr->reserved;
-
-    /* FIXME
-       Assert(pHdr->dwFlags & WHDR_INQUEUE);
-       Assert(!(pHdr->dwFlags & WHDR_COMPLETE));
-    */
-   
-    pHdr->dwFlags |= WHDR_COMPLETE;
-
-    if (pHdr->dwFlags & WHDR_BEGINLOOP) 
-    {
-        PWAVEHDR pHdrSearch;
-        for (pHdrSearch = pClient->DeviceQueue ; pHdrSearch != pHdr ; pHdrSearch = pHdrSearch->lpNext) 
-        {
-            //Assert(pHdrSearch != NULL);
-            pHdrSearch->dwFlags |= WHDR_COMPLETE;
-        }
-    }
-   
-    if (pHdr->dwBufferLength)     
-        pClient->BytesOutstanding -= (pHdr->dwBufferLength - 1) % MAX_BUFFER_SIZE + 1;
-    
-    if (pClient->DeviceType == WaveInDevice)     
-        pHdr->dwBytesRecorded += BytesTransferred;
-    
-    HeapFree(Heap, 0, (LPSTR)pOverlapped);
-
-}
-
-
-
-
-
-static MMRESULT OpenWaveDevice(UINT  DeviceType,
-								DWORD id,
-								DWORD dwUser,
-								DWORD dwParam1,
-								DWORD dwParam2)
-{
-	// TODO: Implement
-    PWAVEALLOC     pClient = (PWAVEALLOC)dwUser;  
-    MMRESULT mResult;
-    BOOL Result;
-    DWORD BytesReturned;
-    LPWAVEFORMATEX pFormats;
-    PWAVEALLOC *pUserHandle = NULL;
-    HANDLE hDevice;
-
-    pFormats = (LPWAVEFORMATEX)((LPWAVEOPENDESC)dwParam1)->lpFormat;
-
-    if (dwParam2 & WAVE_FORMAT_QUERY) 
-    {        
-        mResult = OpenDevice(DeviceType, id, &hDevice, GENERIC_READ);
-        if (mResult != MMSYSERR_NOERROR) 
-            return mResult;
-        
-        Result = DeviceIoControl(hDevice, IOCTL_WAVE_QUERY_FORMAT, (PVOID)pFormats,
-                                 pFormats->wFormatTag == WAVE_FORMAT_PCM ?
-                                 sizeof(PCMWAVEFORMAT) : sizeof(WAVEFORMATEX) + pFormats->cbSize,                        
-                                 NULL, 0, &BytesReturned, NULL);
-        CloseHandle(hDevice);
-        return Result ? MMSYSERR_NOERROR : GetLastError() == ERROR_NOT_SUPPORTED ? WAVERR_BADFORMAT : TranslateStatus();
-    }
-
-    EnterCriticalSection(&CS);
-
-    for (pClient = WaveLists; pClient != NULL; pClient = pClient->Next) 
-    {
-        if (pClient->DeviceNumber == id && pClient->DeviceType == DeviceType) 
-        {        
-            if (pClient->hDev != INVALID_HANDLE_VALUE) 
-            {
-                LeaveCriticalSection(&CS);
-                return MMSYSERR_ALLOCATED;
-            }
-            break;
-        }
-    }
-
-    if (pClient == NULL) 
-    {
-        pClient = (PWAVEALLOC)HeapAlloc(Heap, HEAP_ZERO_MEMORY, sizeof(WAVEALLOC));
-        if (pClient == NULL) 
-        {
-            LeaveCriticalSection(&CS);
-            return MMSYSERR_NOMEM;
-        }
-        
-        pClient->DeviceNumber = id;
-        pClient->Next = WaveLists;
-        pClient->DeviceType = DeviceType;
-        
-        WaveLists = pClient;
-    }
-
-    pClient->hWave       = ((LPWAVEOPENDESC)dwParam1)->hWave;
-    pClient->dwInstance  = ((LPWAVEOPENDESC)dwParam1)->dwInstance;
-    pClient->dwFlags     = dwParam2;
-    pClient->dwCallback  = ((LPWAVEOPENDESC)dwParam1)->dwCallback;
-    pClient->hDev = INVALID_HANDLE_VALUE;
-    pClient->NextBuffer  = NULL;
-    pClient->DeviceQueue = NULL;
-    pClient->LoopHead    = NULL;
-    pClient->LoopCount   = 0;
-    pClient->BytesOutstanding = 0;
-    pClient->BufferPosition = 0;
-    
-    
-    
-
-    mResult = OpenDevice(DeviceType, id, &pClient->hDev, (GENERIC_READ | GENERIC_WRITE));
-
-    if (mResult != MMSYSERR_NOERROR) 
-    {    
-        LeaveCriticalSection(&CS);
-        return mResult;
-    }
-
-     if (!DeviceIoControl(pClient->hDev,IOCTL_WAVE_SET_FORMAT, (PVOID)pFormats,
-                             pFormats->wFormatTag == WAVE_FORMAT_PCM ?
-                             sizeof(PCMWAVEFORMAT) : sizeof(WAVEFORMATEX) + pFormats->cbSize,
-                             NULL, 0, &BytesReturned, NULL))
-    {
-        CloseHandle(pClient->hDev);
-        pClient->hDev = INVALID_HANDLE_VALUE;
-        LeaveCriticalSection(&CS);
-        return GetLastError() == ERROR_NOT_SUPPORTED ? WAVERR_BADFORMAT : TranslateStatus();
-    }
-
-    LeaveCriticalSection(&CS);
-
-    if (!pClient->Event) 
-    {
-        pClient->Event = CreateEvent(NULL, FALSE, FALSE, NULL);
-        if (pClient->Event == NULL) 
-        {
-            // Cleanup
-            return MMSYSERR_NOMEM;
-        }
-
-        pClient->AuxEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
-        if (!pClient->AuxEvent1) 
-        {
-           // Cleanup
-            return MMSYSERR_NOMEM;
-        }
-
-        pClient->AuxEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
-        if (!pClient->AuxEvent2) 
-        {
-            // Cleanup
-            return MMSYSERR_NOMEM;
-        }
-
-
-        mResult = mmTaskCreate((LPTASKCALLBACK)waveThread, &pClient->ThreadHandle, (DWORD)pClient);
-        if ( mResult != MMSYSERR_NOERROR) 
-        {
-            // Cleanup
-            return MMSYSERR_NOMEM;
-        }
-
-        WaitForSingleObject(pClient->AuxEvent2, INFINITE);
-     }
-     
-     *pUserHandle = pClient;
-      pUserHandle = (PWAVEALLOC *)dwUser;
-   
-
-     if (pClient->dwCallback)
-     {
-        DriverCallback(pClient->dwCallback, HIWORD(pClient->dwFlags),
-                       (HDRVR)pClient->hWave,  DeviceType == WaveOutDevice ? WOM_OPEN : WIM_OPEN, 
-                       pClient->dwInstance, 0L, 0L);                 
-     }
-
-	return MMSYSERR_NOERROR;
-}
-
-
-//FIXME: MS-specific code, except for name of the func!
-MMRESULT GetPositionWaveDevice(PWAVEALLOC pClient, LPMMTIME lpmmt, DWORD dwSize)
-{
-	/*
-    WAVE_DD_POSITION PositionData;
-    MMRESULT mErr;
-
-    if (dwSize < sizeof(MMTIME))
-        return MMSYSERR_ERROR;
-
-    //
-    // Get the current position from the driver
-    //
-    mErr = sndGetHandleData(pClient->hDev,
-                            sizeof(PositionData),
-                            &PositionData,
-                            IOCTL_WAVE_GET_POSITION,
-                            pClient->Event);
-
-    if (mErr == MMSYSERR_NOERROR) {
-        if (lpmmt->wType == TIME_BYTES) {
-            lpmmt->u.cb = PositionData.ByteCount;
-        }
-
-        // default is samples.
-        else {
-            lpmmt->wType = TIME_SAMPLES;
-            lpmmt->u.sample = PositionData.SampleCount;
-        }
-    }
-
-    return mErr;*/ return MMSYSERR_NOERROR;
-}
-
-
-
-MMRESULT soundSetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data,
-                     ULONG Ioctl)
-{
-    HANDLE hDevcie;
-    MMRESULT Result;
-    DWORD BytesReturned;
-
-    Result = OpenDevice(DeviceType, DeviceId, &hDevcie, GENERIC_READ);
-    if (Result != MMSYSERR_NOERROR) 
-         return Result;
-
-    Result = DeviceIoControl(hDevcie, Ioctl, Data, Length, NULL, 0, &BytesReturned, NULL) ? 
-                             MMSYSERR_NOERROR : TranslateStatus();
-    CloseHandle(hDevcie);
-
-	return Result;
-}
-
-MMRESULT soundGetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data,
-                     ULONG Ioctl)
-{
-	HANDLE hDevice;
-    MMRESULT Result;
-    DWORD BytesReturned;
-
-    Result = OpenDevice(DeviceType, DeviceId, &hDevice, GENERIC_READ);
-    if (Result != MMSYSERR_NOERROR)     
-         return Result;
-        
-    Result = DeviceIoControl(hDevice, Ioctl, NULL, 0, (LPVOID)Data, Length,
-                           &BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
-    CloseHandle(hDevice);
-    return Result;
-}
-
-
-/* ============================
- *  EXPORT
- *  functions start here
- * ============================
- */
-
-/*
- * @implemented
- */
-APIENTRY DWORD wodMessage(DWORD dwId, DWORD dwMessage, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
-{
-    PWAVEALLOC pTask = (PWAVEALLOC)dwUser;
-
-    switch (dwMessage) {
-        case WODM_GETNUMDEVS:
-            DPRINT("WODM_GETNUMDEVS");
-            return GetDeviceCount(WaveOutDevice);
-
-        case WODM_GETDEVCAPS:
-            DPRINT("WODM_GETDEVCAPS");
-            return GetDeviceCapabilities(dwId, WaveOutDevice, (LPBYTE)dwParam1,
-                                  (DWORD)dwParam2);
-
-        case WODM_OPEN:
-            DPRINT("WODM_OPEN");
-            return OpenWaveDevice(WaveOutDevice, dwId, dwUser, dwParam1, dwParam2);
-
-        case WODM_CLOSE:
-			{	
-				DPRINT("WODM_CLOSE");
-
-				// 1. Check if the task is ready to complete
-                pTask->AuxFunction = WaveThreadClose;
-                SetEvent(pTask->AuxEvent1);
-                WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-	            			
-				if ( pTask->AuxReturnCode != MMSYSERR_NOERROR) 
-                {
-				    return pTask->AuxReturnCode;
-				}
-				else
-					
-                {
-                    if (pTask->dwCallback)
-                    {
-                        DriverCallback(pTask->dwCallback, HIWORD(pTask->dwFlags), (HDRVR)pTask->hWave, 
-                                       WOM_CLOSE, pTask->dwInstance, 0L, 0L);                   
-                    }
-                }
-
-				
-				// 2. Close the device
-				if (pTask->hDev != INVALID_HANDLE_VALUE) {
-					CloseHandle(pTask->hDev);
-
-					EnterCriticalSection(&CS);
-					pTask->hDev = INVALID_HANDLE_VALUE;
-					LeaveCriticalSection(&CS);
-				}
-
-				return MMSYSERR_NOERROR;
-			};
-
-        case WODM_WRITE:
-			{
-				LPWAVEHDR pWaveHdr = (LPWAVEHDR)dwParam1;
-
-				DPRINT("WODM_WRITE");
-
-				if (dwParam1 != 0)
-					return MMSYSERR_INVALPARAM;
-
-				if ((pWaveHdr->dwFlags & ~(WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP)))
-					return MMSYSERR_INVALPARAM;
-
-				pWaveHdr->dwFlags &= (WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP);
-
-				if ((pWaveHdr->dwFlags & WHDR_PREPARED) == 0)
-					return MMSYSERR_INVALPARAM;
-
-				// Check, if the wave header is already prepared
-				if (!(pWaveHdr->dwFlags & WHDR_PREPARED))
-					return WAVERR_UNPREPARED;
-
-				// If it's already located in the queue, this op is impossible
-				if (pWaveHdr->dwFlags & WHDR_INQUEUE )
-					return ( WAVERR_STILLPLAYING );
-
-				// save WAVEALLOC pointer in the WaveHeader
-				pWaveHdr->reserved = dwUser;
-
-				
-                pWaveHdr->dwFlags |= WHDR_INQUEUE;
-                pWaveHdr->dwFlags &= ~WHDR_DONE;
-                pTask->AuxParam.pHdr = pWaveHdr;
-                
-                pTask->AuxFunction = WaveThreadAddBuffer;
-                SetEvent(pTask->AuxEvent1);
-                WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-                return pTask->AuxReturnCode;
-			}
-
-        case WODM_PAUSE:
-            DPRINT("WODM_PAUSE");
-            pTask->AuxParam.State = WAVE_DD_STOP;
-           
-            pTask->AuxFunction = WaveThreadSetState;
-            SetEvent(pTask->AuxEvent1);
-            WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-	        return pTask->AuxReturnCode;
-
-        case WODM_RESTART:
-            DPRINT("WODM_RESTART");
-            pTask->AuxParam.State = WAVE_DD_PLAY;
-
-            pTask->AuxFunction = WaveThreadSetState;
-            SetEvent(pTask->AuxEvent1);
-            WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-	        return pTask->AuxReturnCode;            
-
-        case WODM_RESET:
-            DPRINT("WODM_RESET");
-            pTask->AuxParam.State = WAVE_DD_RESET;
-
-            pTask->AuxFunction = WaveThreadSetState;
-            SetEvent(pTask->AuxEvent1);
-            WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-	        return pTask->AuxReturnCode;
-           
-        case WODM_BREAKLOOP:
-            DPRINT("WODM_BREAKLOOP");
-
-            pTask->AuxFunction = WaveThreadBreakLoop;
-            SetEvent(pTask->AuxEvent1);
-            WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-	        return pTask->AuxReturnCode;
-
-        case WODM_GETPOS:
-            DPRINT("WODM_GETPOS");
-            return GetPositionWaveDevice(pTask, (LPMMTIME)dwParam1, dwParam2);
-
-        case WODM_SETPITCH:
-            DPRINT("WODM_SETPITCH");
-            pTask->AuxParam.GetSetData.pData = (PBYTE)&dwParam1;
-            pTask->AuxParam.GetSetData.DataLen = sizeof(DWORD);
-            pTask->AuxParam.GetSetData.Function = IOCTL_WAVE_SET_PITCH;
-            
-            pTask->AuxFunction = WaveThreadSetData;
-            SetEvent(pTask->AuxEvent1);
-            WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-	        return pTask->AuxReturnCode;
-
-        case WODM_SETVOLUME:
-            DPRINT("WODM_SETVOLUME");
-            {
-                WAVE_DD_VOLUME Vol;
-                Vol.Left = LOWORD(dwParam1) << 16;
-                Vol.Right = HIWORD(dwParam1) << 16;
-
-                return soundSetData(WaveOutDevice, dwId, sizeof(Vol),
-                                  (PBYTE)&Vol, IOCTL_WAVE_SET_VOLUME);
-            }
-
-        case WODM_SETPLAYBACKRATE:
-            DPRINT("WODM_SETPLAYBACKRATE");
-            pTask->AuxParam.GetSetData.pData = (PBYTE)&dwParam1;
-            pTask->AuxParam.GetSetData.DataLen = sizeof(DWORD);
-            pTask->AuxParam.GetSetData.Function = IOCTL_WAVE_SET_PLAYBACK_RATE;
-            
-            pTask->AuxFunction = WaveThreadSetData;
-            SetEvent(pTask->AuxEvent1);
-            WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-	        return pTask->AuxReturnCode;
-
-
-        case WODM_GETPITCH:
-            DPRINT("WODM_GETPITCH");
-            pTask->AuxParam.GetSetData.pData = (PBYTE)dwParam1;
-            pTask->AuxParam.GetSetData.DataLen = sizeof(DWORD);
-            pTask->AuxParam.GetSetData.Function = IOCTL_WAVE_GET_PITCH;
-            
-            pTask->AuxFunction = WaveThreadGetData;
-            SetEvent(pTask->AuxEvent1);
-            WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-	        return pTask->AuxReturnCode;
-
-        case WODM_GETVOLUME:
-            DPRINT("WODM_GETVOLUME");
-            {
-                WAVE_DD_VOLUME Vol = {};
-                DWORD res;
-
-                res = soundGetData(WaveOutDevice, dwId, sizeof(Vol),
-                                (PBYTE)&Vol, IOCTL_WAVE_GET_VOLUME);
-
-                if (res == MMSYSERR_NOERROR)
-                    *(LPDWORD)dwParam1 = (DWORD)MAKELONG(HIWORD(Vol.Left), HIWORD(Vol.Right));
-                
-                return res;
-            }
-
-        case WODM_GETPLAYBACKRATE:
-            DPRINT("WODM_GETPLAYBACKRATE");
-            pTask->AuxParam.GetSetData.pData = (PBYTE)dwParam1;
-            pTask->AuxParam.GetSetData.DataLen = sizeof(DWORD);
-            pTask->AuxParam.GetSetData.Function = IOCTL_WAVE_GET_PLAYBACK_RATE;
-                         
-            pTask->AuxFunction = WaveThreadGetData;
-            SetEvent(pTask->AuxEvent1);
-            WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-	        return pTask->AuxReturnCode;
-
-        default:
-            return MMSYSERR_NOTSUPPORTED;
-    }
-
-	// This point of execution should never be reached
-    return MMSYSERR_NOTSUPPORTED;
-}
-
-
-/*
- * @implemented
- */
-APIENTRY DWORD widMessage(DWORD dwId, DWORD dwMessage, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
-{
-    DPRINT("widMessage\n");
-
-    switch (dwMessage) 
-    {
-        case WIDM_GETNUMDEVS: 
-            DPRINT("WIDM_GETNUMDEVS");
-            return GetDeviceCount(WaveInDevice);
-
-        case WIDM_GETDEVCAPS:
-            DPRINT("WODM_GETDEVCAPS");
-            return GetDeviceCapabilities(dwId, WaveInDevice, (LPBYTE)dwParam1, (DWORD)dwParam2);
-             
-        case WIDM_OPEN:
-            DPRINT("WIDM_OPEN");
-            return OpenWaveDevice(WaveInDevice, dwId, dwUser, dwParam1, dwParam2);
-
-        case WIDM_CLOSE:
-             return MMSYSERR_NOERROR;
-
-        case WIDM_ADDBUFFER:
-             return MMSYSERR_NOERROR;
-
-        case WIDM_STOP:
-             return MMSYSERR_NOERROR;
-
-        case WIDM_START:
-             return MMSYSERR_NOERROR;
-
-        case WIDM_RESET:
-             return MMSYSERR_NOERROR;
-
-        case WIDM_GETPOS:
-             return MMSYSERR_NOERROR;
-
-
-        default :
-             return MMSYSERR_NOTSUPPORTED;
-    }
-}
-
+
+    DPRINT("Wave processing thread setting ready state\n");
+
+    SetEvent(session_info->thread.ready_event);
+
+    while ( ! terminate )
+    {
+        /* Wait for GO event, or IO completion notification */
+        while ( WaitForSingleObjectEx(session_info->thread.go_event,
+                                      INFINITE,
+                                      TRUE) == WAIT_IO_COMPLETION )
+        {
+            /* A buffer has been finished with - pass back to the client */
+            ReturnCompletedBuffers(session_info);
+        }
+
+        DPRINT("Wave processing thread woken up\n");
+
+        /* Set the terminate flag if that's what the caller wants */
+        terminate = (session_info->thread.function == DRVM_TERMINATE);
+
+        /* Process the request */
+        DPRINT("Processing thread request\n");
+        result = ProcessSessionThreadRequest(session_info);
+
+        /* Store the result code */
+        session_info->thread.result = result;
+
+        /* Submit new buffers and continue existing ones */
+        DPRINT("Performing wave I/O\n");
+        PerformWaveIO(session_info);
+
+        /* Now we're ready for more action */
+        DPRINT("Wave processing thread sleeping\n");
+        SetEvent(session_info->thread.ready_event);
+    }
+
+    return 0;
+}
+
+
+/*
+    Convenience function for calculating the size of the WAVEFORMATEX struct.
+*/
+
+DWORD
+GetWaveFormatExSize(PWAVEFORMATEX format)
+{
+    if ( format->wFormatTag == WAVE_FORMAT_PCM )
+        return sizeof(PCMWAVEFORMAT);
+    else
+        return sizeof(WAVEFORMATEX) + format->cbSize;
+}
+
+
+/*
+    Query if the driver/device is capable of handling a format. This is called
+    if the device is a wave device, and the QUERYFORMAT flag is set.
+*/
+
+DWORD
+QueryWaveFormat(
+    DeviceType device_type,
+    PVOID lpFormat)
+{
+    /* TODO */
+    return WAVERR_BADFORMAT;
+}
+
+
+/*
+    Set the format to be used.
+*/
+
+BOOL
+SetWaveFormat(
+    HANDLE device_handle,
+    PWAVEFORMATEX format)
+{
+    DWORD bytes_returned;
+    DWORD size;
+
+    size = GetWaveFormatExSize(format);
+
+    DPRINT("SetWaveFormat\n");
+
+    return DeviceIoControl(device_handle,
+                           IOCTL_WAVE_SET_FORMAT,
+                           (PVOID) format,
+                           size,
+                           NULL,
+                           0,
+                           &bytes_returned,
+                           NULL);
+}
+
+
+DWORD
+WriteWaveBuffer(
+    DWORD private_handle,
+    PWAVEHDR wave_header,
+    DWORD wave_header_size)
+{
+    SessionInfo* session_info = (SessionInfo*) private_handle;
+    ASSERT(session_info);
+
+    /* Let the processing thread know that it has work to do */
+    return CallSessionThread(session_info, WODM_WRITE, wave_header);
+}

Added: trunk/reactos/dll/win32/mmdrv/wave_io.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/wave_io.c?rev=27384&view=auto
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/wave_io.c (added)
+++ trunk/reactos/dll/win32/mmdrv/wave_io.c Wed Jul  4 14:17:48 2007
@@ -1,0 +1,40 @@
+/*
+    Don't use this.
+*/
+
+#include <mmdrv.h>
+
+/*
+    Complete a partial wave buffer transaction
+*/
+
+void
+CompleteWaveOverlap(
+    DWORD error_code,
+    DWORD bytes_transferred,
+    LPOVERLAPPED overlapped)
+{
+    DPRINT("Complete partial wave overlap\n");
+}
+
+/*
+    Helper function to set up loops
+*/
+
+VOID
+UpdateWaveLoop(SessionInfo* session_info)
+{
+}
+
+
+/*
+    The hub of all wave I/O. This ensures a constant stream of buffers are
+    passed between the land of usermode and kernelmode.
+*/
+
+VOID
+PerformWaveIO(
+    SessionInfo* session_info)
+{
+
+}




More information about the Ros-diffs mailing list