Added PCM converter internal driver.
A few driver handling fixes.

diff --git a/dlls/msacm/Makefile.in b/dlls/msacm/Makefile.in
index f1478f1..06eca80 100644
--- a/dlls/msacm/Makefile.in
+++ b/dlls/msacm/Makefile.in
@@ -14,6 +14,7 @@
 	internal.c \
 	msacm32_main.c \
 	msacm_main.c \
+	pcmconverter.c \
 	stream.c
 
 RC_SRCS = \
diff --git a/dlls/msacm/driver.c b/dlls/msacm/driver.c
index abca669..112f033 100644
--- a/dlls/msacm/driver.c
+++ b/dlls/msacm/driver.c
@@ -76,27 +76,32 @@
  */
 MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose)
 {
-    PWINE_ACMDRIVER  p;
-    PWINE_ACMDRIVER* tp;
-    
+    PWINE_ACMDRIVER	pad;
+    PWINE_ACMDRIVERID	padid;
+    PWINE_ACMDRIVER*	tpad;
+
     if (fdwClose)
 	return MMSYSERR_INVALFLAG;
     
-    p = MSACM_GetDriver(had);
-    if (!p)
+    pad = MSACM_GetDriver(had);
+    if (!pad)
 	return MMSYSERR_INVALHANDLE;
 
-    for (tp = &(p->obj.pACMDriverID->pACMDriverList); *tp; *tp = (*tp)->pNextACMDriver) {
-	if (*tp == p) {
-	    *tp = (*tp)->pNextACMDriver;
+    padid = pad->obj.pACMDriverID;
+
+    /* remove driver from list */
+    for (tpad = &(padid->pACMDriverList); *tpad; *tpad = (*tpad)->pNextACMDriver) {
+	if (*tpad == pad) {
+	    *tpad = (*tpad)->pNextACMDriver;
 	    break;
 	}
     }
     
-    if (p->hDrvr && !p->obj.pACMDriverID->pACMDriverList)
-	CloseDriver(p->hDrvr, 0, 0);
+    /* close driver if it has been opened */
+    if (pad->hDrvr && !padid->hInstModule)
+	CloseDriver(pad->hDrvr, 0, 0);
     
-    HeapFree(MSACM_hHeap, 0, p);
+    HeapFree(MSACM_hHeap, 0, pad);
     
     return MMSYSERR_NOERROR;
 }
@@ -232,30 +237,25 @@
     if (!phad)
 	return MMSYSERR_INVALPARAM;
     
+    if (fdwOpen)
+	return MMSYSERR_INVALFLAG;
+    
     padid = MSACM_GetDriverID(hadid); 
     if (!padid)
 	return MMSYSERR_INVALHANDLE;
     
-    if (fdwOpen)
-	return MMSYSERR_INVALFLAG;
-    
     pad = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
     if (!pad) return MMSYSERR_NOMEM;
 
     pad->obj.dwType = WINE_ACMOBJ_DRIVER;
     pad->obj.pACMDriverID = padid;
     
-    if (!padid->hInstModule)
-	pad->hDrvr = OpenDriverA(padid->pszDriverAlias, "drivers32", 0);
-    else
-	pad->hDrvr = padid->hInstModule;
-    
+    if (!(pad->hDrvr = padid->hInstModule) && padid->pszDriverAlias)
+	pad->hDrvr = OpenDriverA(padid->pszDriverAlias, NULL, 0);
     if (!pad->hDrvr) {
 	HeapFree(MSACM_hHeap, 0, pad);
 	return MMSYSERR_ERROR;
     }
-    
-    pad->pfnDriverProc = GetProcAddress(pad->hDrvr, "DriverProc");
 
     /* insert new pad at beg of list */
     pad->pNextACMDriver = padid->pACMDriverList;
@@ -263,7 +263,7 @@
 
     /* FIXME: Create a WINE_ACMDRIVER32 */
     *phad = (HACMDRIVER)pad;
-    
+    TRACE("'%s' => %08lx\n", padid->pszDriverAlias, (DWORD)pad);
     return MMSYSERR_NOERROR;
 }
 
diff --git a/dlls/msacm/format.c b/dlls/msacm/format.c
index 8d28e47..b1fe666 100644
--- a/dlls/msacm/format.c
+++ b/dlls/msacm/format.c
@@ -484,7 +484,7 @@
 
     if (fdwEnum & (ACM_FORMATENUMF_CONVERT|ACM_FORMATENUMF_SUGGEST|
 		   ACM_FORMATENUMF_INPUT|ACM_FORMATENUMF_OUTPUT))
-	FIXME("Unsupported fdwEnum values\n");
+	FIXME("Unsupported fdwEnum values %08lx\n", fdwEnum);
 
     if (had) {
 	HACMDRIVERID	hadid;
diff --git a/dlls/msacm/internal.c b/dlls/msacm/internal.c
index e9d2bd3..293513c 100644
--- a/dlls/msacm/internal.c
+++ b/dlls/msacm/internal.c
@@ -42,8 +42,8 @@
     padid = (PWINE_ACMDRIVERID) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID));
     padid->obj.dwType = WINE_ACMOBJ_DRIVERID;
     padid->obj.pACMDriverID = padid;
-    padid->pszDriverAlias = HEAP_strdupA(MSACM_hHeap, 0, pszDriverAlias);
-    padid->pszFileName = HEAP_strdupA(MSACM_hHeap, 0, pszFileName);
+    padid->pszDriverAlias = pszDriverAlias ? HEAP_strdupA(MSACM_hHeap, 0, pszDriverAlias) : NULL;
+    padid->pszFileName = pszFileName ? HEAP_strdupA(MSACM_hHeap, 0, pszFileName) : NULL;
     padid->hInstModule = hinstModule;
     padid->bEnabled = TRUE;
     padid->pACMDriverList = NULL;
@@ -65,7 +65,7 @@
 {
     LPSTR pszBuffer;
     DWORD dwBufferLength;
-    
+
     /* FIXME 
      *  What if the user edits system.ini while the program is running?
      *  Does Windows handle that?
@@ -85,8 +85,9 @@
 		char *s2 = s;
 		while (*s2 != '\0' && *s2 != '=') s2++;
 		if (*s2) {
-		    *s2++ = '\0';
-		    MSACM_RegisterDriver(s, s2, 0);
+		    *s2 = '\0';
+		    MSACM_RegisterDriver(s, s2 + 1, 0);
+		    *s2 = '=';
 		}
 	    }  
 	    s += strlen(s) + 1; /* Either next char or \0 */
@@ -94,6 +95,8 @@
     }
     
     HeapFree(MSACM_hHeap, 0, pszBuffer);
+
+    MSACM_RegisterDriver("msacm32.dll", "msacm32.dll", 0);
 }
 
 /***********************************************************************
diff --git a/dlls/msacm/msacm32.spec b/dlls/msacm/msacm32.spec
index b3cc6bd..13e297c 100644
--- a/dlls/msacm/msacm32.spec
+++ b/dlls/msacm/msacm32.spec
@@ -51,3 +51,6 @@
 42 stdcall acmStreamReset(long long) acmStreamReset
 43 stdcall acmStreamSize(long long ptr long) acmStreamSize
 44 stdcall acmStreamUnprepareHeader(long ptr long) acmStreamUnprepareHeader
+
+# this is wine only
+@ stdcall DriverProc(long long long long long) PCM_DriverProc
diff --git a/dlls/msacm/pcmconverter.c b/dlls/msacm/pcmconverter.c
new file mode 100644
index 0000000..1184f19
--- /dev/null
+++ b/dlls/msacm/pcmconverter.c
@@ -0,0 +1,450 @@
+/* -*- tab-width: 8; c-basic-offset: 4 -*- */
+
+/*
+ *      MSACM32 library
+ *
+ *      Copyright 2000		Eric Pouech
+ */
+
+#include <assert.h>
+#include "wine/winestring.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "msacm.h"
+#include "msacmdrv.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(msacm);
+
+static	DWORD	PCM_drvOpen(LPCSTR str)
+{
+    return 1;
+}
+
+static	DWORD	PCM_drvClose(DWORD dwDevID)
+{
+    return 1;
+}
+
+static	struct {
+    int		nChannels;
+    int		nBits;
+    int		rate;
+} PCM_Formats[] = {
+    {1,  8,  8000},
+    {2,  8,  8000},
+    {1, 16,  8000},
+    {2, 16,  8000},
+    {1,  8, 11025},
+    {2,  8, 11025},
+    {1, 16, 11025},
+    {2, 16, 11025},
+    {1,  8, 22050},
+    {2,  8, 22050},
+    {1, 16, 22050},
+    {2, 16, 22050},
+    {1,  8, 44100},
+    {2,  8, 44100},
+    {1, 16, 44100},
+    {2, 16, 44100},
+};
+
+#define	NUM_PCM_FORMATS	(sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
+
+static	DWORD	PCM_GetFormatIndex(LPWAVEFORMATEX wfx)
+{
+    int i;
+    
+    for (i = 0; i < NUM_PCM_FORMATS; i++) {
+	if (wfx->nChannels == PCM_Formats[i].nChannels &&
+	    wfx->nSamplesPerSec == PCM_Formats[i].rate &&
+	    wfx->wBitsPerSample == PCM_Formats[i].nBits)
+	    return i;
+    }
+    return 0xFFFFFFFF;
+}
+
+static	LRESULT PCM_DriverDetails(PACMDRIVERDETAILSW add)
+{
+    add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
+    add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
+    add->wMid = 0xFF;
+    add->wPid = 0x00;
+    add->vdwACM = 0x01000000;
+    add->vdwDriver = 0x01000000;
+    add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
+    add->cFormatTags = 1;
+    add->cFilterTags = 0;
+    add->hicon = (HICON)0;
+    lstrcpyAtoW(add->szShortName, "WINE-PCM");
+    lstrcpyAtoW(add->szLongName, "Wine PCM converter");
+    lstrcpyAtoW(add->szCopyright, "Brought to you by the Wine team...");
+    lstrcpyAtoW(add->szLicensing, "Refer to LICENSE file");
+    add->szFeatures[0] = 0;
+    
+    return MMSYSERR_NOERROR;
+}
+
+static	LRESULT	PCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
+{
+    switch (dwQuery) {
+    case ACM_FORMATTAGDETAILSF_INDEX:
+	if (aftd->dwFormatTagIndex != 0) return ACMERR_NOTPOSSIBLE;
+	break;
+    case ACM_FORMATTAGDETAILSF_FORMATTAG: 
+	if (aftd->dwFormatTag != WAVE_FORMAT_PCM) return ACMERR_NOTPOSSIBLE;
+	break;
+    case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
+	if (aftd->dwFormatTag != WAVE_FORMAT_UNKNOWN && aftd->dwFormatTag != WAVE_FORMAT_UNKNOWN)
+	    return ACMERR_NOTPOSSIBLE;
+	break;
+    default:
+	WARN("Unsupported query %08lx\n", dwQuery);
+	return MMSYSERR_NOTSUPPORTED;
+    }
+    
+    aftd->dwFormatTagIndex = 0;
+    aftd->dwFormatTag = WAVE_FORMAT_PCM;
+    aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
+    aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
+    aftd->cStandardFormats = NUM_PCM_FORMATS;
+    aftd->szFormatTag[0] = 0;
+    
+    return MMSYSERR_NOERROR;
+}
+
+static	LRESULT	PCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
+{
+    switch (dwQuery) {
+    case ACM_FORMATDETAILSF_FORMAT:
+	afd->dwFormatIndex = PCM_GetFormatIndex(afd->pwfx);
+	if (afd->dwFormatIndex == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
+	break;
+    case ACM_FORMATDETAILSF_INDEX:
+	assert(afd->dwFormatIndex < NUM_PCM_FORMATS);
+	afd->pwfx->wFormatTag = WAVE_FORMAT_PCM;
+	afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
+	afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
+	afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
+	/* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
+	   afd->pwfx->cbSize = 0; 
+	*/
+	afd->pwfx->nBlockAlign = (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
+	afd->pwfx->nAvgBytesPerSec = afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
+	break;
+    default:
+	WARN("Unsupported query %08lx\n", dwQuery);
+	return MMSYSERR_NOTSUPPORTED;	
+    }
+    
+    afd->dwFormatTag = WAVE_FORMAT_PCM;
+    afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
+    afd->szFormat[0] = 0; /* let MSACM format this for us... */
+    
+    return MMSYSERR_NOERROR;
+}
+
+static	LRESULT	PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
+{
+    FIXME("(%p);\n", adfs);
+    return MMSYSERR_NOTSUPPORTED;
+}
+
+static	LRESULT	PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
+{
+    assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
+    
+    if (PCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
+	PCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
+	return ACMERR_NOTPOSSIBLE;
+    return MMSYSERR_NOERROR;
+}
+
+static	LRESULT	PCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
+{
+    return MMSYSERR_NOERROR;
+}
+
+static	inline DWORD	PCM_round(DWORD a, DWORD b, DWORD c)
+{
+    assert(a && b && c);
+    /* to be sure, always return an entire number of c... */
+    return (a * b + c - 1) / c;
+}
+
+static	LRESULT PCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss)
+{
+    switch (adss->fdwSize) {
+    case ACM_STREAMSIZEF_DESTINATION:
+	/* cbDstLength => cbSrcLength */
+	adss->cbSrcLength = PCM_round(adss->cbDstLength, adsi->pwfxSrc->nAvgBytesPerSec, adsi->pwfxDst->nAvgBytesPerSec);
+	break;
+    case ACM_STREAMSIZEF_SOURCE:
+	/* cbSrcLength => cbDstLength */
+	adss->cbDstLength =  PCM_round(adss->cbSrcLength, adsi->pwfxDst->nAvgBytesPerSec, adsi->pwfxSrc->nAvgBytesPerSec);
+	break;
+    default:
+	WARN("Unsupported query %08lx\n", adss->fdwSize);
+	return MMSYSERR_NOTSUPPORTED;	
+    }
+    return MMSYSERR_NOERROR;
+}
+
+/*
+  parameters :
+  8 bit unsigned vs 16 bit signed (-32 / +32k ???)
+  mono vs stereo
+  sampling rate (8.0, 11.025, 22.05, 44.1 kHz)
+*/
+
+static	void cvtMS88K(const unsigned char* src, int ns, unsigned char* dst)
+{
+    while (ns--) {
+	*dst++ = *src;
+	*dst++ = *src++;
+    }
+}
+
+static	void cvtMS816K(const unsigned char* src, int ns, short* dst)
+{
+    int	v;
+    
+    while (ns--) {
+	v = ((short)(*src++) ^ 0x80) * 256;
+	*dst++ = LOBYTE(v);
+	*dst++ = HIBYTE(v);
+	*dst++ = LOBYTE(v);
+	*dst++ = HIBYTE(v);
+    }
+}
+
+static	void cvtMS168K(const short* src, int ns, unsigned char* dst)
+{
+    unsigned char v;
+    
+    while (ns--) {
+	v = HIBYTE(*src++) ^ 0x80;
+	*dst++ = v;
+	*dst++ = v;
+    }
+}
+
+static	void cvtMS1616K(const short* src, int ns, short* dst)
+{
+    while (ns--) {
+	*dst++ = *src;
+	*dst++ = *src++;
+    }
+}
+
+static	void cvtSM88K(const unsigned char* src, int ns, unsigned char* dst)
+{
+    while (ns--) {
+	*dst++ = (src[0] + src[1]) / 2;
+	src += 2;
+    }
+}
+
+static	void cvtSM816K(const unsigned char* src, int ns, short* dst)
+{
+    int	v;
+    
+    while (ns--) {
+	v = (((short)(src[0]) ^ 0x80) * 256 + ((short)(src[1]) ^ 0x80) * 256) / 2;
+	src += 2;
+	*dst++ = LOBYTE(v);
+	*dst++ = HIBYTE(v);
+    }
+}
+
+static	void cvtSM168K(const short* src, int ns, unsigned char* dst)
+{
+    unsigned char v;
+    
+    while (ns--) {
+	v = ((HIBYTE(src[0]) ^ 0x80) + (HIBYTE(src[1]) ^ 0x80)) / 2;
+	src += 2;
+	*dst++ = v;
+    }
+}
+
+static	void cvtSM1616K(const short* src, int ns, short* dst)
+{
+    while (ns--) {
+	*dst++ = (src[0] + src[1]) / 2;
+	src += 2;
+    }
+}
+
+static	void cvtMM816K(const unsigned char* src, int ns, short* dst)
+{
+    int	v;
+    
+    while (ns--) {
+	v = ((short)(*src++) ^ 0x80) * 256;
+	*dst++ = LOBYTE(v);
+	*dst++ = HIBYTE(v);
+    }
+}
+
+static	void cvtSS816K(const unsigned char* src, int ns, short* dst)
+{
+    int	v;
+    
+    while (ns--) {
+	v = ((short)(*src++) ^ 0x80) * 256;
+	*dst++ = LOBYTE(v);
+	*dst++ = HIBYTE(v);
+	v = ((short)(*src++) ^ 0x80) * 256;
+	*dst++ = LOBYTE(v);
+	*dst++ = HIBYTE(v);
+    }
+}
+
+static	void cvtMM168K(const short* src, int ns, unsigned char* dst)
+{
+    while (ns--) {
+	*dst++ = HIBYTE(*src++) ^ 0x80;
+    }
+}
+
+static	void cvtSS168K(const short* src, int ns, unsigned char* dst)
+{
+    while (ns--) {
+	*dst++ = HIBYTE(*src++) ^ 0x80;
+	*dst++ = HIBYTE(*src++) ^ 0x80;
+    }
+}
+
+static	LRESULT	PCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
+{
+    /* do the job */
+    if (adsi->pwfxSrc->nSamplesPerSec == adsi->pwfxDst->nSamplesPerSec) {
+	/* easy case */
+	if (adsi->pwfxSrc->wBitsPerSample == adsi->pwfxDst->wBitsPerSample &&
+	    adsi->pwfxSrc->nChannels == adsi->pwfxDst->nChannels) {
+	    memcpy(adsh->pbDst, adsh->pbSrc, adsh->cbSrcLength);
+	} else if (adsi->pwfxSrc->wBitsPerSample == 8 &&
+	    adsi->pwfxDst->wBitsPerSample == 8) {
+	    if (adsi->pwfxSrc->nChannels == 1 &&
+		adsi->pwfxDst->nChannels == 2)
+		cvtMS88K(adsh->pbSrc, adsh->cbSrcLength, adsh->pbDst);
+	    else if (adsi->pwfxSrc->nChannels == 2 &&
+		     adsi->pwfxDst->nChannels == 1)
+		cvtSM88K(adsh->pbSrc, adsh->cbSrcLength / 2, adsh->pbDst);
+	} else if (adsi->pwfxSrc->wBitsPerSample == 8 &&
+		   adsi->pwfxDst->wBitsPerSample == 16) {
+	    if (adsi->pwfxSrc->nChannels == 1 &&
+		adsi->pwfxDst->nChannels == 1)
+		cvtMM816K(adsh->pbSrc, adsh->cbSrcLength, (short*)adsh->pbDst);
+	    else if (adsi->pwfxSrc->nChannels == 1 &&
+		     adsi->pwfxDst->nChannels == 2)
+		cvtMS816K(adsh->pbSrc, adsh->cbSrcLength, (short*)adsh->pbDst);
+	    else if (adsi->pwfxSrc->nChannels == 2 &&
+		     adsi->pwfxDst->nChannels == 1)
+		cvtSM816K(adsh->pbSrc, adsh->cbSrcLength / 2, (short*)adsh->pbDst);
+	    else if (adsi->pwfxSrc->nChannels == 2 &&
+		     adsi->pwfxDst->nChannels == 2)
+		cvtSS816K(adsh->pbSrc, adsh->cbSrcLength / 2, (short*)adsh->pbDst);
+	} else if (adsi->pwfxSrc->wBitsPerSample == 16 &&
+		   adsi->pwfxDst->wBitsPerSample == 8) {
+	    if (adsi->pwfxSrc->nChannels == 1 &&
+		adsi->pwfxDst->nChannels == 1)
+		cvtMM168K((short*)adsh->pbSrc, adsh->cbSrcLength / 2, adsh->pbDst);
+	    else if (adsi->pwfxSrc->nChannels == 1 &&
+		     adsi->pwfxDst->nChannels == 2)
+		cvtMS168K((short*)adsh->pbSrc, adsh->cbSrcLength / 2, adsh->pbDst);
+	    else if (adsi->pwfxSrc->nChannels == 2 &&
+		     adsi->pwfxDst->nChannels == 1)
+		cvtSM168K((short*)adsh->pbSrc, adsh->cbSrcLength / 4, adsh->pbDst);
+	    else if (adsi->pwfxSrc->nChannels == 2 &&
+		     adsi->pwfxDst->nChannels == 2)
+		cvtSS168K((short*)adsh->pbSrc, adsh->cbSrcLength / 4, adsh->pbDst);
+	} else if (adsi->pwfxSrc->wBitsPerSample == 16 &&
+		   adsi->pwfxDst->wBitsPerSample == 16) {
+	    if (adsi->pwfxSrc->nChannels == 1 &&
+		adsi->pwfxDst->nChannels == 2)
+		cvtMS1616K((short*)adsh->pbSrc, adsh->cbSrcLength / 2, (short*)adsh->pbDst);
+	    else if (adsi->pwfxSrc->nChannels == 2 &&
+		     adsi->pwfxDst->nChannels == 1)
+		cvtSM1616K((short*)adsh->pbSrc, adsh->cbSrcLength / 4, (short*)adsh->pbDst);
+	} else FIXME("NIY\n");
+	/* FIXME: rounding shall be taken care off... */
+	adsh->cbSrcLengthUsed = adsh->cbSrcLength;
+	adsh->cbDstLengthUsed = (adsh->cbSrcLength * adsi->pwfxDst->nBlockAlign) / adsi->pwfxSrc->nBlockAlign;
+	
+    } else {
+	FIXME("NIY\n");
+	return MMSYSERR_NOTSUPPORTED;
+    }
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+ * 			PCM_DriverProc			[exported]
+ */
+LRESULT CALLBACK	PCM_DriverProc(DWORD dwDevID, HDRVR hDriv, UINT wMsg, 
+				       LPARAM dwParam1, LPARAM dwParam2)
+{
+    TRACE("(%08lx %08lx %u %08lx %08lx);\n", 
+	  dwDevID, (DWORD)hDriv, wMsg, dwParam1, dwParam2);
+    
+    switch (wMsg) {
+    case DRV_LOAD:		return 1;
+    case DRV_FREE:		return 1;
+    case DRV_OPEN:		return PCM_drvOpen((LPSTR)dwParam1);
+    case DRV_CLOSE:		return PCM_drvClose(dwDevID);
+    case DRV_ENABLE:		return 1;	
+    case DRV_DISABLE:		return 1;
+    case DRV_QUERYCONFIGURE:	return 1;
+    case DRV_CONFIGURE:		MessageBoxA(0, "MSACM PCM filter !", "Wine Driver", MB_OK); return 1;
+    case DRV_INSTALL:		return DRVCNF_RESTART;
+    case DRV_REMOVE:		return DRVCNF_RESTART;
+	
+    case ACMDM_DRIVER_NOTIFY:
+	/* no caching from other ACM drivers is done so far */
+	return MMSYSERR_NOERROR;
+	
+    case ACMDM_DRIVER_DETAILS:
+	return PCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
+	
+    case ACMDM_FORMATTAG_DETAILS:
+	return PCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
+	
+    case ACMDM_FORMAT_DETAILS:
+	return PCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
+	
+    case ACMDM_FORMAT_SUGGEST:
+	return PCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
+	
+    case ACMDM_STREAM_OPEN:
+	return PCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
+	
+    case ACMDM_STREAM_CLOSE:
+	return PCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
+	
+    case ACMDM_STREAM_SIZE:
+	return PCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
+	
+    case ACMDM_STREAM_CONVERT:
+	return PCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
+	
+    case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
+    case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
+	/* this converter is not a hardware driver */
+    case ACMDM_FILTERTAG_DETAILS:
+    case ACMDM_FILTER_DETAILS:
+	/* this converter is not a filter */
+    case ACMDM_STREAM_RESET:
+	/* only needed for asynchronous driver... we aren't, so just say it */
+    case ACMDM_STREAM_PREPARE:
+    case ACMDM_STREAM_UNPREPARE:
+	/* nothing special to do here... so don't do anything */
+	return MMSYSERR_NOTSUPPORTED;
+	
+    default:
+	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
+    }
+    return 0;
+}
diff --git a/dlls/msacm/wineacm.h b/dlls/msacm/wineacm.h
index 4356cc6..3595abf 100644
--- a/dlls/msacm/wineacm.h
+++ b/dlls/msacm/wineacm.h
@@ -285,7 +285,6 @@
 {
     WINE_ACMOBJ		obj;
     HDRVR      		hDrvr;
-    DRIVERPROC		pfnDriverProc;
     PWINE_ACMDRIVER	pNextACMDriver;
 } WINE_ACMDRIVER;
 
@@ -328,6 +327,10 @@
 /* From msacm32.c */
 extern HINSTANCE MSACM_hInstance32;
 
+/* From pcmcnvtr.c */
+LRESULT CALLBACK	PCM_DriverProc(DWORD dwDevID, HDRVR hDriv, UINT wMsg, 
+				       LPARAM dwParam1, LPARAM dwParam2);
+
 /* Dialog box templates */
 #define DLG_ACMFORMATCHOOSE_ID              70
 #define IDD_ACMFORMATCHOOSE_BTN_HELP        9