Index: trunk/src/winmm/wavemap/initterm.cpp
===================================================================
--- trunk/src/winmm/wavemap/initterm.cpp	(revision 2459)
+++ trunk/src/winmm/wavemap/initterm.cpp	(revision 2459)
@@ -0,0 +1,104 @@
+/* $Id: initterm.cpp,v 1.1 2000-01-17 05:22:59 sandervl Exp $ */
+
+/*
+ * DLL entry point
+ *
+ * Copyright 1998 Sander van Leeuwen
+ * Copyright 1998 Peter Fitzsimmons
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+/*-------------------------------------------------------------*/
+/* INITERM.C -- Source for a custom dynamic link library       */
+/*              initialization and termination (_DLL_InitTerm) */
+/*              function.                                      */
+/*                                                             */
+/* When called to perform initialization, this sample function */
+/* gets storage for an array of integers, and initializes its  */
+/* elements with random integers.  At termination time, it     */
+/* frees the array.  Substitute your own special processing.   */
+/*-------------------------------------------------------------*/
+
+
+/* Include files */
+#define  INCL_DOSMODULEMGR
+#define  INCL_DOSPROCESS
+#include <os2wrap.h>    //Odin32 OS/2 api wrappers
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <odin.h>
+#include <misc.h>       /*PLF Wed  98-03-18 23:18:15*/
+
+extern "C" {
+void CDECL _ctordtorInit( void );
+void CDECL _ctordtorTerm( void );
+}
+
+/*-------------------------------------------------------------------*/
+/* A clean up routine registered with DosExitList must be used if    */
+/* runtime calls are required and the runtime is dynamically linked. */
+/* This will guarantee that this clean up routine is run before the  */
+/* library DLL is terminated.                                        */
+/*-------------------------------------------------------------------*/
+static void APIENTRY cleanup(ULONG reason);
+
+
+/****************************************************************************/
+/* _DLL_InitTerm is the function that gets called by the operating system   */
+/* loader when it loads and frees this DLL for each process that accesses   */
+/* this DLL.  However, it only gets called the first time the DLL is loaded */
+/* and the last time it is freed for a particular process.  The system      */
+/* linkage convention MUST be used because the operating system loader is   */
+/* calling this function.                                                   */
+/****************************************************************************/
+unsigned long SYSTEM _DLL_InitTerm(unsigned long hModule, unsigned long
+                                   ulFlag)
+{
+   size_t i;
+   APIRET rc;
+
+   /*-------------------------------------------------------------------------*/
+   /* If ulFlag is zero then the DLL is being loaded so initialization should */
+   /* be performed.  If ulFlag is 1 then the DLL is being freed so            */
+   /* termination should be performed.                                        */
+   /*-------------------------------------------------------------------------*/
+
+   switch (ulFlag) {
+      case 0 :
+         _ctordtorInit();
+
+         CheckVersionFromHMOD(PE2LX_VERSION, hModule); /*PLF Wed  98-03-18 05:28:48*/
+
+         /*******************************************************************/
+         /* A DosExitList routine must be used to clean up if runtime calls */
+         /* are required and the runtime is dynamically linked.             */
+         /*******************************************************************/
+
+         rc = DosExitList(0x0000F000|EXLST_ADD, cleanup);
+         if(rc)
+                return 0UL;
+
+         break;
+      case 1 :
+         break;
+      default  :
+         return 0UL;
+   }
+
+   /***********************************************************/
+   /* A non-zero value must be returned to indicate success.  */
+   /***********************************************************/
+   return 1UL;
+}
+
+
+static void APIENTRY cleanup(ULONG ulReason)
+{
+   _ctordtorTerm();
+   DosExitList(EXLST_EXIT, cleanup);
+   return ;
+}
Index: trunk/src/winmm/wavemap/makefile
===================================================================
--- trunk/src/winmm/wavemap/makefile	(revision 2459)
+++ trunk/src/winmm/wavemap/makefile	(revision 2459)
@@ -0,0 +1,51 @@
+# $Id: makefile,v 1.1 2000-01-17 05:23:00 sandervl Exp $
+
+#
+# PD-Win32 API
+#
+#	msacm32.drv makefile
+#
+
+PDWIN32_INCLUDE = ..\..\include
+PDWIN32_LIB = ..\..\lib
+PDWIN32_BIN = ..\..\bin
+
+
+!include $(PDWIN32_INCLUDE)/pdwin32.mk
+
+
+CFLAGS = $(CFLAGS) -I$(PDWIN32_INCLUDE)
+CXXFLAGS = $(CXXFLAGS) -I$(PDWIN32_INCLUDE)
+
+
+TARGET = msacm32
+
+OBJS =  msacm32.obj initterm.obj
+
+all: $(TARGET).drv $(TARGET).lib
+
+
+$(TARGET).drv: $(OBJS) $(TARGET).def
+	$(LD) $(LDFLAGS) -Fm -Fe$@ $(OBJS) $(TARGET).def \
+              $(PDWIN32_LIB)/pmwinx.lib $(PDWIN32_LIB)/kernel32.lib \
+              $(PDWIN32_LIB)/user32.lib $(PDWIN32_LIB)/winmm.lib $(PDWIN32_LIB)/odincrt.lib OS2386.LIB $(RTLLIB_O)
+	$(CP) $@ $(PDWIN32_BIN)
+
+
+$(TARGET).lib: $(TARGET).def
+	$(IMPLIB) $(IMPLIBFLAGS) $@ $**
+	$(CP) $@ $(PDWIN32_LIB)
+
+
+initterm.obj: initterm.cpp
+msacm32.obj: msacm32.cpp
+
+clean:
+	$(RM) *.obj *.lib *.drv *~ *.map *.pch
+	$(RM) $(PDWIN32_BIN)\$(TARGET).drv
+	$(RM) $(PDWIN32_LIB)\$(TARGET).lib
+
+
+
+
+
Index: trunk/src/winmm/wavemap/msacm32.cpp
===================================================================
--- trunk/src/winmm/wavemap/msacm32.cpp	(revision 2459)
+++ trunk/src/winmm/wavemap/msacm32.cpp	(revision 2459)
@@ -0,0 +1,560 @@
+/* -*- tab-width: 8; c-basic-offset: 4 -*- */
+/*				   
+ * Wine Wave mapper driver
+ *
+ * Copyright 	1999 Eric Pouech
+ */
+
+/* TODOs
+ *	+ implement wavein as waveout has been implemented
+ *	+ better protection against evilish dwUser parameters
+ *	+ use asynchronous ACM conversion
+ */
+
+#include <os2win.h>
+#include <string.h>
+#include "winuser.h"
+#include "driver.h"
+#include "mmddk.h"
+#include "msacm.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(msacm)
+
+typedef	struct tagWAVEMAPDATA {
+    struct tagWAVEMAPDATA*	self;
+    HWAVE	hWave;
+    HACMSTREAM	hAcmStream;
+    /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
+    DWORD	dwCallback;
+    DWORD	dwClientInstance;
+    DWORD	dwFlags;
+    MMRESULT (WINAPI *acmStreamOpen)(LPHACMSTREAM, HACMDRIVER, LPWAVEFORMATEX, LPWAVEFORMATEX, LPWAVEFILTER, DWORD, DWORD, DWORD);
+    MMRESULT (WINAPI *acmStreamClose)(HACMSTREAM, DWORD);
+    MMRESULT (WINAPI *acmStreamSize)(HACMSTREAM, DWORD, LPDWORD, DWORD);
+    MMRESULT (WINAPI *acmStreamConvert)(HACMSTREAM, PACMSTREAMHEADER, DWORD);
+    MMRESULT (WINAPI *acmStreamPrepareHeader)(HACMSTREAM, PACMSTREAMHEADER, DWORD);
+    MMRESULT (WINAPI *acmStreamUnprepareHeader)(HACMSTREAM, PACMSTREAMHEADER, DWORD);
+} WAVEMAPDATA;
+
+static	BOOL	WAVEMAP_IsData(WAVEMAPDATA* wm)
+{
+    return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
+}
+
+/*======================================================================*
+ *                  WAVE OUT part                                       *
+ *======================================================================*/
+
+static void	CALLBACK WAVEMAP_DstCallback(HDRVR hDev, UINT uMsg, DWORD dwInstance, 
+					     DWORD dwParam1, DWORD dwParam2)
+{
+    WAVEMAPDATA*	wom = (WAVEMAPDATA*)dwInstance;
+
+    TRACE("(0x%x %u %ld %ld %ld);\n", hDev, uMsg, dwInstance, dwParam1, dwParam2);
+
+    switch (uMsg) {
+    case WOM_OPEN:
+    case WOM_CLOSE:
+	/* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
+	break;
+    case WOM_DONE:
+	{
+	    LPWAVEHDR		lpWaveHdrDst = (LPWAVEHDR)dwParam1;
+	    PACMSTREAMHEADER	ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
+	    LPWAVEHDR		lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;
+
+	    lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
+	    lpWaveHdrSrc->dwFlags |= WHDR_DONE;
+	    dwParam1 = (DWORD)lpWaveHdrSrc;
+	}
+	break;
+    default:
+	ERR("Unknown msg %u\n", uMsg);
+    }
+
+    DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), hDev, uMsg, 
+		   wom->dwClientInstance, dwParam1, dwParam2);
+}
+
+static	DWORD	wodOpenHelper(WAVEMAPDATA* wom, UINT idx, 
+			      LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, 
+			      DWORD dwFlags)
+{
+    DWORD	ret;
+
+    /* destination is always PCM, so the formulas below apply */
+    lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
+    lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
+    ret = wom->acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 
+			     (dwFlags & WAVE_FORMAT_QUERY) ? ACM_STREAMOPENF_QUERY : 0L);
+    if (ret != MMSYSERR_NOERROR)
+	return ret;
+    return waveOutOpen(&wom->hWave, idx, lpwfx, (DWORD)WAVEMAP_DstCallback, 
+		       (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
+}
+
+static	DWORD	wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
+{
+    UINT 		nd = waveOutGetNumDevs();
+    UINT		i;
+    WAVEMAPDATA*	wom = (WAVEMAPDATA*)HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
+    WAVEFORMATEX	wfx;
+
+    TRACE("(%p %p %08lx\n", lpdwUser, lpDesc, dwFlags);
+
+    if (!wom)
+	return MMSYSERR_NOMEM;
+
+    wom->self = wom;
+
+    for (i = 0; i < nd; i++) {
+	/* if no ACM stuff is involved, no need to handle callbacks at this
+	 * level, this will be done transparently
+	 */
+	if (waveOutOpen(&wom->hWave, i, lpDesc->lpFormat, lpDesc->dwCallback, 
+			lpDesc->dwInstance, dwFlags) == MMSYSERR_NOERROR) {
+	    wom->hAcmStream = 0;
+	    goto found;
+	}
+    }
+
+    /* temporary hack until real builtin dll loading is available */
+    do {
+	HMODULE hModule = LoadLibraryA("msacm32.dll");
+	
+	*(VOID **)wom->acmStreamOpen            = (void*)GetProcAddress(hModule, "acmStreamOpen");
+	*(VOID **)wom->acmStreamClose           = (void*)GetProcAddress(hModule, "acmStreamClose");
+	*(VOID **)wom->acmStreamSize            = (void*)GetProcAddress(hModule, "acmStreamSize");
+	*(VOID **)wom->acmStreamConvert         = (void*)GetProcAddress(hModule, "acmStreamConvert");
+	*(VOID **)wom->acmStreamPrepareHeader   = (void*)GetProcAddress(hModule, "acmStreamPrepareHeader");
+	*(VOID **)wom->acmStreamUnprepareHeader = (void*)GetProcAddress(hModule, "acmStreamUnprepareHeader");
+    } while (0);
+
+    wfx.wFormatTag = WAVE_FORMAT_PCM;
+    wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
+    /* try some ACM stuff */
+
+    wom->dwCallback = lpDesc->dwCallback;
+    wom->dwFlags = dwFlags;
+    wom->dwClientInstance = lpDesc->dwInstance;
+
+#define	TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
+                        if (wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags) == MMSYSERR_NOERROR) goto found;
+
+    for (i = 0; i < nd; i++) {
+	/* first try with same stereo/mono option as source */
+	wfx.nChannels = lpDesc->lpFormat->nChannels;
+	TRY(44100, 8);
+	TRY(22050, 8);
+	TRY(11025, 8);
+
+	/* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
+	wfx.nChannels ^= 3; 
+	TRY(44100, 8);
+	TRY(22050, 8);
+	TRY(11025, 8);
+    }
+#undef TRY
+		      
+    HeapFree(GetProcessHeap(), 0, wom);
+    return MMSYSERR_ALLOCATED;
+found:
+    if (dwFlags & WAVE_FORMAT_QUERY) {
+	lpDesc->hWave = 0;
+	*lpdwUser = 0L;
+	HeapFree(GetProcessHeap(), 0, wom);
+    } else {
+	lpDesc->hWave = wom->hWave;
+	*lpdwUser = (DWORD)wom;
+    }
+    return MMSYSERR_NOERROR;
+}
+
+static	DWORD	wodClose(WAVEMAPDATA* wom)
+{
+    DWORD ret = waveOutClose(wom->hWave);
+
+    if (ret == MMSYSERR_NOERROR) {
+	if (wom->hAcmStream) {
+	    ret = wom->acmStreamClose(wom->hAcmStream, 0);
+	}
+	if (ret == MMSYSERR_NOERROR) {
+	    HeapFree(GetProcessHeap(), 0, wom);
+	}
+    }
+    return ret;
+}
+
+static	DWORD	wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
+{
+    PACMSTREAMHEADER	ash;
+    LPWAVEHDR		lpWaveHdrDst;
+
+    if (!wom->hAcmStream) {
+	return waveOutWrite(wom->hWave, lpWaveHdrSrc, dwParam2);
+    }
+    
+    lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;
+    ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
+    if (wom->acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR)
+	return MMSYSERR_ERROR;
+    
+    lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
+    lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;
+    return waveOutWrite(wom->hWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
+}
+
+static	DWORD	wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
+{
+    PACMSTREAMHEADER	ash;
+    DWORD		size;
+    DWORD		dwRet;
+    LPWAVEHDR		lpWaveHdrDst;
+
+    if (!wom->hAcmStream) {
+	return waveOutPrepareHeader(wom->hWave, lpWaveHdrSrc, dwParam2);
+    }
+    if (wom->acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR)
+	return MMSYSERR_ERROR;
+
+    ash = (_ACMSTREAMHEADER*)HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
+    if (ash == NULL)
+	return MMSYSERR_NOMEM;
+
+    ash->cbStruct = sizeof(*ash);
+    ash->fdwStatus = 0L;
+    ash->dwUser = (DWORD)lpWaveHdrSrc;
+    ash->pbSrc = (BYTE*)lpWaveHdrSrc->lpData;
+    ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
+    /* ash->cbSrcLengthUsed */
+    ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */
+    ash->pbDst = (BYTE*)((LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR));
+    ash->cbDstLength = size;
+    /* ash->cbDstLengthUsed */
+    ash->dwDstUser = 0; /* FIXME ? */
+    dwRet = wom->acmStreamPrepareHeader(wom->hAcmStream, ash, 0L);
+    if (dwRet != MMSYSERR_NOERROR)
+	goto errCleanUp;
+
+    lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
+    lpWaveHdrDst->lpData = (CHAR*)ash->pbDst;
+    lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */
+    lpWaveHdrDst->dwFlags = 0;
+    lpWaveHdrDst->dwLoops = 0;
+    dwRet = waveOutPrepareHeader(wom->hWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
+    if (dwRet != MMSYSERR_NOERROR)
+	goto errCleanUp;
+
+    lpWaveHdrSrc->reserved = (DWORD)ash;
+    lpWaveHdrSrc->dwFlags = WHDR_PREPARED;
+    TRACE("=> (0)\n");
+    return MMSYSERR_NOERROR;
+errCleanUp:
+    TRACE("=> (%ld)\n", dwRet);
+    HeapFree(GetProcessHeap(), 0, ash);
+    return dwRet;
+}
+
+static	DWORD	wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
+{
+    PACMSTREAMHEADER	ash;
+    LPWAVEHDR		lpWaveHdrDst;
+    DWORD		dwRet1, dwRet2;
+
+    if (!wom->hAcmStream) {
+	return waveOutUnprepareHeader(wom->hWave, lpWaveHdrSrc, dwParam2);
+    }
+    ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
+    dwRet1 = wom->acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L);
+    
+    lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
+    dwRet2 = waveOutUnprepareHeader(wom->hWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
+
+    HeapFree(GetProcessHeap(), 0, ash);
+    
+    lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED;
+    return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
+}
+
+static	DWORD	wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
+{
+    return waveOutGetPosition(wom->hWave, lpTime, dwParam2);
+}
+
+static	DWORD	wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSA lpWaveCaps, DWORD dwParam2)
+{
+    /* if opened low driver, forward message */
+    if (WAVEMAP_IsData(wom))
+	return waveOutGetDevCapsA(wom->hWave, lpWaveCaps, dwParam2);
+    /* otherwise, return caps of mapper itself */
+    if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
+	lpWaveCaps->wMid = 0x00FF;
+	lpWaveCaps->wPid = 0x0001;
+	lpWaveCaps->vDriverVersion = 0x0100;
+	strcpy(lpWaveCaps->szPname, "Wine wave out mapper");
+	lpWaveCaps->dwFormats = 
+	    WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
+	    WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
+	    WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
+	lpWaveCaps->wChannels = 2;
+	lpWaveCaps->dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
+
+	return MMSYSERR_NOERROR;
+    }
+    ERR("This shouldn't happen\n");
+    return MMSYSERR_ERROR; 
+}
+
+static	DWORD	wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
+{
+    if (WAVEMAP_IsData(wom))
+	return waveOutGetVolume(wom->hWave, lpVol);
+    return MMSYSERR_NOERROR;
+}
+
+static	DWORD	wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
+{
+    if (WAVEMAP_IsData(wom))
+	return waveOutSetVolume(wom->hWave, vol);
+    return MMSYSERR_NOERROR;
+}
+
+static	DWORD	wodPause(WAVEMAPDATA* wom)
+{
+    return waveOutPause(wom->hWave);
+}
+
+static	DWORD	wodRestart(WAVEMAPDATA* wom)
+{
+    return waveOutRestart(wom->hWave);
+}
+
+static	DWORD	wodReset(WAVEMAPDATA* wom)
+{
+    return waveOutReset(wom->hWave);
+}
+
+/**************************************************************************
+ * 				WAVEMAP_wodMessage	[sample driver]
+ */
+DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 
+				DWORD dwParam1, DWORD dwParam2)
+{
+    TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
+	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
+    
+    switch (wMsg) {
+    case DRVM_INIT:
+    case DRVM_EXIT:
+    case DRVM_ENABLE:
+    case DRVM_DISABLE:
+	/* FIXME: Pretend this is supported */
+	return 0;
+    case WODM_OPEN:	 	return wodOpen		((LPDWORD)dwUser,      (LPWAVEOPENDESC)dwParam1,dwParam2);
+    case WODM_CLOSE:	 	return wodClose		((WAVEMAPDATA*)dwUser);
+    case WODM_WRITE:	 	return wodWrite		((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,	dwParam2);
+    case WODM_PAUSE:	 	return wodPause		((WAVEMAPDATA*)dwUser);
+    case WODM_GETPOS:	 	return wodGetPosition	((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, 	dwParam2);
+    case WODM_BREAKLOOP: 	return MMSYSERR_NOTSUPPORTED;
+    case WODM_PREPARE:	 	return wodPrepare	((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
+    case WODM_UNPREPARE: 	return wodUnprepare	((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
+    case WODM_GETDEVCAPS:	return wodGetDevCaps	(wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSA)dwParam1,dwParam2);
+    case WODM_GETNUMDEVS:	return 1;
+    case WODM_GETPITCH:	 	return MMSYSERR_NOTSUPPORTED;
+    case WODM_SETPITCH:	 	return MMSYSERR_NOTSUPPORTED;
+    case WODM_GETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
+    case WODM_SETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
+    case WODM_GETVOLUME:	return wodGetVolume	(wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
+    case WODM_SETVOLUME:	return wodSetVolume	(wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
+    case WODM_RESTART:		return wodRestart	((WAVEMAPDATA*)dwUser);
+    case WODM_RESET:		return wodReset		((WAVEMAPDATA*)dwUser);
+    default:
+	FIXME("unknown message %d!\n", wMsg);
+    }
+    return MMSYSERR_NOTSUPPORTED;
+}
+
+/*======================================================================*
+ *                  WAVE IN part                                        *
+ *======================================================================*/
+
+static	DWORD	widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
+{
+    UINT 		nd = waveInGetNumDevs();
+    UINT		i;
+    WAVEMAPDATA*	wim = (WAVEMAPDATA*)HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
+
+    TRACE("(%p %p %08lx\n", lpdwUser, lpDesc, dwFlags);
+
+    wim->self = wim;
+
+    for (i = 0; i < nd; i++) {
+	if (waveInOpen(&wim->hWave, i, lpDesc->lpFormat, lpDesc->dwCallback, 
+			lpDesc->dwInstance, dwFlags) == MMSYSERR_NOERROR) {
+	    lpDesc->hWave = wim->hWave;
+	    *lpdwUser = (DWORD)wim;
+	    return MMSYSERR_NOERROR;
+	}
+    }
+    HeapFree(GetProcessHeap(), 0, wim);
+    return MMSYSERR_ALLOCATED;
+}
+
+static	DWORD	widClose(WAVEMAPDATA* wim)
+{
+    DWORD ret = waveInClose(wim->hWave);
+    if (ret == MMSYSERR_NOERROR)
+	HeapFree(GetProcessHeap(), 0, wim);
+    return ret;
+}
+
+static	DWORD	widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdr, DWORD dwParam2)
+{
+    return waveInAddBuffer(wim->hWave, lpWaveHdr, dwParam2);
+}
+
+static	DWORD	widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdr, DWORD dwParam2)
+{
+    return waveInPrepareHeader(wim->hWave, lpWaveHdr, dwParam2);
+}
+
+static	DWORD	widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdr, DWORD dwParam2)
+{
+    return waveInUnprepareHeader(wim->hWave, lpWaveHdr, dwParam2);
+}
+
+static	DWORD	widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
+{
+    return waveInGetPosition(wim->hWave, lpTime, dwParam2);
+}
+
+static	DWORD	widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSA lpWaveCaps, DWORD dwParam2)
+{
+    /* if opened low driver, forward message */
+    if (WAVEMAP_IsData(wim))
+	return waveInGetDevCapsA(wim->hWave, lpWaveCaps, dwParam2);
+    /* otherwise, return caps of mapper itself */
+    if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
+	lpWaveCaps->wMid = 0x00FF;
+	lpWaveCaps->wPid = 0x0001;
+	lpWaveCaps->vDriverVersion = 0x0001;
+	strcpy(lpWaveCaps->szPname, "Wine wave in mapper");
+	lpWaveCaps->dwFormats = 
+	    WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
+	    WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
+	    WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;    
+	lpWaveCaps->wChannels = 2;
+	return MMSYSERR_NOERROR;
+    }
+    ERR("This shouldn't happen\n");
+    return MMSYSERR_ERROR; 
+}
+
+static	DWORD	widStop(WAVEMAPDATA* wim)
+{
+    return waveInStop(wim->hWave);
+}
+
+static	DWORD	widStart(WAVEMAPDATA* wim)
+{
+    return waveInStart(wim->hWave);
+}
+
+static	DWORD	widReset(WAVEMAPDATA* wim)
+{
+    return waveInReset(wim->hWave);
+}
+
+/**************************************************************************
+ * 				WAVEMAP_widMessage	[sample driver]
+ */
+DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+				DWORD dwParam1, DWORD dwParam2)
+{
+    TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
+	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
+
+    switch (wMsg) {
+    case DRVM_INIT:
+    case DRVM_EXIT:
+    case DRVM_ENABLE:
+    case DRVM_DISABLE:
+	/* FIXME: Pretend this is supported */
+	return 0;
+
+    case WIDM_OPEN:		return widOpen          ((LPDWORD)dwUser,     (LPWAVEOPENDESC)dwParam1, dwParam2);
+    case WIDM_CLOSE:		return widClose         ((WAVEMAPDATA*)dwUser);
+
+    case WIDM_ADDBUFFER:	return widAddBuffer     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
+    case WIDM_PREPARE:		return widPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
+    case WIDM_UNPREPARE:	return widUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
+    case WIDM_GETDEVCAPS:	return widGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSA)dwParam1, dwParam2);
+    case WIDM_GETNUMDEVS:	return 1;
+    case WIDM_GETPOS:		return widGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, 	dwParam2);
+    case WIDM_RESET:		return widReset         ((WAVEMAPDATA*)dwUser);
+    case WIDM_START:		return widStart         ((WAVEMAPDATA*)dwUser);
+    case WIDM_STOP:		return widStop          ((WAVEMAPDATA*)dwUser);
+    default:
+	FIXME("unknown message %u!\n", wMsg);
+    }
+    return MMSYSERR_NOTSUPPORTED;
+}
+
+/*======================================================================*
+ *                  Driver part                                         *
+ *======================================================================*/
+
+static	struct WINE_WAVEMAP* oss = NULL;
+
+/**************************************************************************
+ * 				WAVEMAP_drvOpen			[internal]	
+ */
+static	DWORD	WAVEMAP_drvOpen(LPSTR str)
+{
+    if (oss)
+	return 0;
+    
+    /* I know, this is ugly, but who cares... */
+    oss = (struct WINE_WAVEMAP*)1;
+    return 1;
+}
+
+/**************************************************************************
+ * 				WAVEMAP_drvClose		[internal]	
+ */
+static	DWORD	WAVEMAP_drvClose(DWORD dwDevID)
+{
+    if (oss) {
+	oss = NULL;
+	return 1;
+    }
+    return 0;
+}
+
+/**************************************************************************
+ * 				WAVEMAP_DriverProc		[internal]
+ */
+LONG CALLBACK	WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
+				   DWORD dwParam1, DWORD dwParam2)
+{
+/* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
+/* EPP 	  dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
+    
+    switch(wMsg) {
+    case DRV_LOAD:		return 1;
+    case DRV_FREE:		return 1;
+    case DRV_OPEN:		return WAVEMAP_drvOpen((LPSTR)dwParam1);
+    case DRV_CLOSE:		return WAVEMAP_drvClose(dwDevID);
+    case DRV_ENABLE:		return 1;
+    case DRV_DISABLE:		return 1;
+    case DRV_QUERYCONFIGURE:	return 1;
+    case DRV_CONFIGURE:		MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "OSS Driver", MB_OK);	return 1;
+    case DRV_INSTALL:		return DRVCNF_RESTART;
+    case DRV_REMOVE:		return DRVCNF_RESTART;
+    default:
+	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
+    }
+}
+
+
Index: trunk/src/winmm/wavemap/msacm32.def
===================================================================
--- trunk/src/winmm/wavemap/msacm32.def	(revision 2459)
+++ trunk/src/winmm/wavemap/msacm32.def	(revision 2459)
@@ -0,0 +1,9 @@
+; $Id: msacm32.def,v 1.1 2000-01-17 05:23:00 sandervl Exp $
+
+;Created by BLAST for IBM's compiler
+LIBRARY MSACM32 INITINSTANCE
+DATA MULTIPLE NONSHARED
+
+
+EXPORTS
+    DriverProc		= _WAVEMAP_DriverProc@20		@1
