No longer directly accessing debuggee memory.
[wine] / dlls / winmm / wavemap / wavemap.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*                                 
3  * Wine Wave mapper driver
4  *
5  * Copyright    1999 Eric Pouech
6  */
7
8 /* TODOs
9  *      + implement wavein as waveout has been implemented
10  *      + better protection against evilish dwUser parameters
11  *      + use asynchronous ACM conversion
12  */
13
14 #include "windef.h"
15 #include "wingdi.h"
16 #include "winuser.h"
17 #include "driver.h"
18 #include "mmddk.h"
19 #include "msacm.h"
20 #include "debugtools.h"
21
22 DEFAULT_DEBUG_CHANNEL(msacm)
23
24 typedef struct tagWAVEMAPDATA {
25     struct tagWAVEMAPDATA*      self;
26     HWAVE       hWave;
27     HACMSTREAM  hAcmStream;
28     /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
29     DWORD       dwCallback;
30     DWORD       dwClientInstance;
31     DWORD       dwFlags;
32     MMRESULT (WINAPI *acmStreamOpen)(LPHACMSTREAM, HACMDRIVER, LPWAVEFORMATEX, LPWAVEFORMATEX, LPWAVEFILTER, DWORD, DWORD, DWORD);
33     MMRESULT (WINAPI *acmStreamClose)(HACMSTREAM, DWORD);
34     MMRESULT (WINAPI *acmStreamSize)(HACMSTREAM, DWORD, LPDWORD, DWORD);
35     MMRESULT (WINAPI *acmStreamConvert)(HACMSTREAM, PACMSTREAMHEADER, DWORD);
36     MMRESULT (WINAPI *acmStreamPrepareHeader)(HACMSTREAM, PACMSTREAMHEADER, DWORD);
37     MMRESULT (WINAPI *acmStreamUnprepareHeader)(HACMSTREAM, PACMSTREAMHEADER, DWORD);
38 } WAVEMAPDATA;
39
40 static  BOOL    WAVEMAP_IsData(WAVEMAPDATA* wm)
41 {
42     return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
43 }
44
45 /*======================================================================*
46  *                  WAVE OUT part                                       *
47  *======================================================================*/
48
49 static void     CALLBACK WAVEMAP_DstCallback(HDRVR hDev, UINT uMsg, DWORD dwInstance, 
50                                              DWORD dwParam1, DWORD dwParam2)
51 {
52     WAVEMAPDATA*        wom = (WAVEMAPDATA*)dwInstance;
53
54     TRACE("(0x%x %u %ld %lx %lx);\n", hDev, uMsg, dwInstance, dwParam1, dwParam2);
55
56     switch (uMsg) {
57     case WOM_OPEN:
58     case WOM_CLOSE:
59         /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
60         break;
61     case WOM_DONE:
62         {
63             LPWAVEHDR           lpWaveHdrDst = (LPWAVEHDR)dwParam1;
64             PACMSTREAMHEADER    ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
65             LPWAVEHDR           lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;
66
67             lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
68             lpWaveHdrSrc->dwFlags |= WHDR_DONE;
69             dwParam1 = (DWORD)lpWaveHdrSrc;
70         }
71         break;
72     default:
73         ERR("Unknown msg %u\n", uMsg);
74     }
75
76     DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), hDev, uMsg, 
77                    wom->dwClientInstance, dwParam1, dwParam2);
78 }
79
80 static  DWORD   wodOpenHelper(WAVEMAPDATA* wom, UINT idx, 
81                               LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, 
82                               DWORD dwFlags)
83 {
84     DWORD       ret;
85
86     /* destination is always PCM, so the formulas below apply */
87     lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
88     lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
89     ret = wom->acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 
90                              (dwFlags & WAVE_FORMAT_QUERY) ? ACM_STREAMOPENF_QUERY : 0L);
91     if (ret != MMSYSERR_NOERROR)
92         return ret;
93     return waveOutOpen(&wom->hWave, idx, lpwfx, (DWORD)WAVEMAP_DstCallback, 
94                        (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
95 }
96
97 static  DWORD   wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
98 {
99     UINT                nd = waveOutGetNumDevs();
100     UINT                i;
101     WAVEMAPDATA*        wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
102     WAVEFORMATEX        wfx;
103
104     TRACE("(%p %p %08lx\n", lpdwUser, lpDesc, dwFlags);
105
106     if (!wom)
107         return MMSYSERR_NOMEM;
108
109     wom->self = wom;
110
111     for (i = 0; i < nd; i++) {
112         /* if no ACM stuff is involved, no need to handle callbacks at this
113          * level, this will be done transparently
114          */
115         if (waveOutOpen(&wom->hWave, i, lpDesc->lpFormat, lpDesc->dwCallback, 
116                         lpDesc->dwInstance, dwFlags) == MMSYSERR_NOERROR) {
117             wom->hAcmStream = 0;
118             goto found;
119         }
120     }
121
122     /* temporary hack until real builtin dll loading is available */
123     do {
124         HMODULE hModule = LoadLibraryA("msacm32.dll");
125         
126         wom->acmStreamOpen            = (void*)GetProcAddress(hModule, "acmStreamOpen");
127         wom->acmStreamClose           = (void*)GetProcAddress(hModule, "acmStreamClose");
128         wom->acmStreamSize            = (void*)GetProcAddress(hModule, "acmStreamSize");
129         wom->acmStreamConvert         = (void*)GetProcAddress(hModule, "acmStreamConvert");
130         wom->acmStreamPrepareHeader   = (void*)GetProcAddress(hModule, "acmStreamPrepareHeader");
131         wom->acmStreamUnprepareHeader = (void*)GetProcAddress(hModule, "acmStreamUnprepareHeader");
132     } while (0);
133
134     wfx.wFormatTag = WAVE_FORMAT_PCM;
135     wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
136     /* try some ACM stuff */
137
138     wom->dwCallback = lpDesc->dwCallback;
139     wom->dwFlags = dwFlags;
140     wom->dwClientInstance = lpDesc->dwInstance;
141
142 #define TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
143                         if (wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags) == MMSYSERR_NOERROR) goto found;
144
145     for (i = 0; i < nd; i++) {
146         /* first try with same stereo/mono option as source */
147         wfx.nChannels = lpDesc->lpFormat->nChannels;
148         TRY(44100, 8);
149         TRY(22050, 8);
150         TRY(11025, 8);
151
152         /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
153         wfx.nChannels ^= 3; 
154         TRY(44100, 8);
155         TRY(22050, 8);
156         TRY(11025, 8);
157     }
158 #undef TRY
159                       
160     HeapFree(GetProcessHeap(), 0, wom);
161     return MMSYSERR_ALLOCATED;
162 found:
163     if (dwFlags & WAVE_FORMAT_QUERY) {
164         lpDesc->hWave = 0;
165         *lpdwUser = 0L;
166         HeapFree(GetProcessHeap(), 0, wom);
167     } else {
168         lpDesc->hWave = wom->hWave;
169         *lpdwUser = (DWORD)wom;
170     }
171     return MMSYSERR_NOERROR;
172 }
173
174 static  DWORD   wodClose(WAVEMAPDATA* wom)
175 {
176     DWORD ret = waveOutClose(wom->hWave);
177
178     if (ret == MMSYSERR_NOERROR) {
179         if (wom->hAcmStream) {
180             ret = wom->acmStreamClose(wom->hAcmStream, 0);
181         }
182         if (ret == MMSYSERR_NOERROR) {
183             HeapFree(GetProcessHeap(), 0, wom);
184         }
185     }
186     return ret;
187 }
188
189 static  DWORD   wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
190 {
191     PACMSTREAMHEADER    ash;
192     LPWAVEHDR           lpWaveHdrDst;
193
194     if (!wom->hAcmStream) {
195         return waveOutWrite(wom->hWave, lpWaveHdrSrc, dwParam2);
196     }
197     
198     lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;
199     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
200     if (wom->acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR)
201         return MMSYSERR_ERROR;
202     
203     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
204     lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;
205     return waveOutWrite(wom->hWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
206 }
207
208 static  DWORD   wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
209 {
210     PACMSTREAMHEADER    ash;
211     DWORD               size;
212     DWORD               dwRet;
213     LPWAVEHDR           lpWaveHdrDst;
214
215     if (!wom->hAcmStream) {
216         return waveOutPrepareHeader(wom->hWave, lpWaveHdrSrc, dwParam2);
217     }
218     if (wom->acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR)
219         return MMSYSERR_ERROR;
220
221     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
222     if (ash == NULL)
223         return MMSYSERR_NOMEM;
224
225     ash->cbStruct = sizeof(*ash);
226     ash->fdwStatus = 0L;
227     ash->dwUser = (DWORD)lpWaveHdrSrc;
228     ash->pbSrc = lpWaveHdrSrc->lpData;
229     ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
230     /* ash->cbSrcLengthUsed */
231     ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */
232     ash->pbDst = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
233     ash->cbDstLength = size;
234     /* ash->cbDstLengthUsed */
235     ash->dwDstUser = 0; /* FIXME ? */
236     dwRet = wom->acmStreamPrepareHeader(wom->hAcmStream, ash, 0L);
237     if (dwRet != MMSYSERR_NOERROR)
238         goto errCleanUp;
239
240     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
241     lpWaveHdrDst->lpData = ash->pbDst;
242     lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */
243     lpWaveHdrDst->dwFlags = 0;
244     lpWaveHdrDst->dwLoops = 0;
245     dwRet = waveOutPrepareHeader(wom->hWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
246     if (dwRet != MMSYSERR_NOERROR)
247         goto errCleanUp;
248
249     lpWaveHdrSrc->reserved = (DWORD)ash;
250     lpWaveHdrSrc->dwFlags = WHDR_PREPARED;
251     TRACE("=> (0)\n");
252     return MMSYSERR_NOERROR;
253 errCleanUp:
254     TRACE("=> (%ld)\n", dwRet);
255     HeapFree(GetProcessHeap(), 0, ash);
256     return dwRet;
257 }
258
259 static  DWORD   wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
260 {
261     PACMSTREAMHEADER    ash;
262     LPWAVEHDR           lpWaveHdrDst;
263     DWORD               dwRet1, dwRet2;
264
265     if (!wom->hAcmStream) {
266         return waveOutUnprepareHeader(wom->hWave, lpWaveHdrSrc, dwParam2);
267     }
268     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
269     dwRet1 = wom->acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L);
270     
271     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
272     dwRet2 = waveOutUnprepareHeader(wom->hWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
273
274     HeapFree(GetProcessHeap(), 0, ash);
275     
276     lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED;
277     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
278 }
279
280 static  DWORD   wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
281 {
282     return waveOutGetPosition(wom->hWave, lpTime, dwParam2);
283 }
284
285 static  DWORD   wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSA lpWaveCaps, DWORD dwParam2)
286 {
287     /* if opened low driver, forward message */
288     if (WAVEMAP_IsData(wom))
289         return waveOutGetDevCapsA(wom->hWave, lpWaveCaps, dwParam2);
290     /* otherwise, return caps of mapper itself */
291     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
292         lpWaveCaps->wMid = 0x00FF;
293         lpWaveCaps->wPid = 0x0001;
294         lpWaveCaps->vDriverVersion = 0x0100;
295         strcpy(lpWaveCaps->szPname, "Wine wave out mapper");
296         lpWaveCaps->dwFormats = 
297             WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
298             WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
299             WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
300         lpWaveCaps->wChannels = 2;
301         lpWaveCaps->dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
302
303         return MMSYSERR_NOERROR;
304     }
305     ERR("This shouldn't happen\n");
306     return MMSYSERR_ERROR; 
307 }
308
309 static  DWORD   wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
310 {
311     if (WAVEMAP_IsData(wom))
312         return waveOutGetVolume(wom->hWave, lpVol);
313     return MMSYSERR_NOERROR;
314 }
315
316 static  DWORD   wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
317 {
318     if (WAVEMAP_IsData(wom))
319         return waveOutSetVolume(wom->hWave, vol);
320     return MMSYSERR_NOERROR;
321 }
322
323 static  DWORD   wodPause(WAVEMAPDATA* wom)
324 {
325     return waveOutPause(wom->hWave);
326 }
327
328 static  DWORD   wodRestart(WAVEMAPDATA* wom)
329 {
330     return waveOutRestart(wom->hWave);
331 }
332
333 static  DWORD   wodReset(WAVEMAPDATA* wom)
334 {
335     return waveOutReset(wom->hWave);
336 }
337
338 static  DWORD   wodBreakLoop(WAVEMAPDATA* wom)
339 {
340     return waveOutBreakLoop(wom->hWave);
341 }
342
343 /**************************************************************************
344  *                              WAVEMAP_wodMessage      [sample driver]
345  */
346 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 
347                                 DWORD dwParam1, DWORD dwParam2)
348 {
349     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
350           wDevID, wMsg, dwUser, dwParam1, dwParam2);
351     
352     switch (wMsg) {
353     case DRVM_INIT:
354     case DRVM_EXIT:
355     case DRVM_ENABLE:
356     case DRVM_DISABLE:
357         /* FIXME: Pretend this is supported */
358         return 0;
359     case WODM_OPEN:             return wodOpen          ((LPDWORD)dwUser,      (LPWAVEOPENDESC)dwParam1,dwParam2);
360     case WODM_CLOSE:            return wodClose         ((WAVEMAPDATA*)dwUser);
361     case WODM_WRITE:            return wodWrite         ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
362     case WODM_PAUSE:            return wodPause         ((WAVEMAPDATA*)dwUser);
363     case WODM_GETPOS:           return wodGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,      dwParam2);
364     case WODM_BREAKLOOP:        return wodBreakLoop     ((WAVEMAPDATA*)dwUser);
365     case WODM_PREPARE:          return wodPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
366     case WODM_UNPREPARE:        return wodUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
367     case WODM_GETDEVCAPS:       return wodGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSA)dwParam1,dwParam2);
368     case WODM_GETNUMDEVS:       return 1;
369     case WODM_GETPITCH:         return MMSYSERR_NOTSUPPORTED;
370     case WODM_SETPITCH:         return MMSYSERR_NOTSUPPORTED;
371     case WODM_GETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
372     case WODM_SETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
373     case WODM_GETVOLUME:        return wodGetVolume     (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
374     case WODM_SETVOLUME:        return wodSetVolume     (wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
375     case WODM_RESTART:          return wodRestart       ((WAVEMAPDATA*)dwUser);
376     case WODM_RESET:            return wodReset         ((WAVEMAPDATA*)dwUser);
377     default:
378         FIXME("unknown message %d!\n", wMsg);
379     }
380     return MMSYSERR_NOTSUPPORTED;
381 }
382
383 /*======================================================================*
384  *                  WAVE IN part                                        *
385  *======================================================================*/
386
387 static  DWORD   widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
388 {
389     UINT                nd = waveInGetNumDevs();
390     UINT                i;
391     WAVEMAPDATA*        wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
392
393     TRACE("(%p %p %08lx\n", lpdwUser, lpDesc, dwFlags);
394
395     wim->self = wim;
396
397     for (i = 0; i < nd; i++) {
398         if (waveInOpen(&wim->hWave, i, lpDesc->lpFormat, lpDesc->dwCallback, 
399                         lpDesc->dwInstance, dwFlags) == MMSYSERR_NOERROR) {
400             lpDesc->hWave = wim->hWave;
401             *lpdwUser = (DWORD)wim;
402             return MMSYSERR_NOERROR;
403         }
404     }
405     HeapFree(GetProcessHeap(), 0, wim);
406     return MMSYSERR_ALLOCATED;
407 }
408
409 static  DWORD   widClose(WAVEMAPDATA* wim)
410 {
411     DWORD ret = waveInClose(wim->hWave);
412     if (ret == MMSYSERR_NOERROR)
413         HeapFree(GetProcessHeap(), 0, wim);
414     return ret;
415 }
416
417 static  DWORD   widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdr, DWORD dwParam2)
418 {
419     return waveInAddBuffer(wim->hWave, lpWaveHdr, dwParam2);
420 }
421
422 static  DWORD   widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdr, DWORD dwParam2)
423 {
424     return waveInPrepareHeader(wim->hWave, lpWaveHdr, dwParam2);
425 }
426
427 static  DWORD   widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdr, DWORD dwParam2)
428 {
429     return waveInUnprepareHeader(wim->hWave, lpWaveHdr, dwParam2);
430 }
431
432 static  DWORD   widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
433 {
434     return waveInGetPosition(wim->hWave, lpTime, dwParam2);
435 }
436
437 static  DWORD   widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSA lpWaveCaps, DWORD dwParam2)
438 {
439     /* if opened low driver, forward message */
440     if (WAVEMAP_IsData(wim))
441         return waveInGetDevCapsA(wim->hWave, lpWaveCaps, dwParam2);
442     /* otherwise, return caps of mapper itself */
443     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
444         lpWaveCaps->wMid = 0x00FF;
445         lpWaveCaps->wPid = 0x0001;
446         lpWaveCaps->vDriverVersion = 0x0001;
447         strcpy(lpWaveCaps->szPname, "Wine wave in mapper");
448         lpWaveCaps->dwFormats = 
449             WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
450             WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
451             WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;    
452         lpWaveCaps->wChannels = 2;
453         return MMSYSERR_NOERROR;
454     }
455     ERR("This shouldn't happen\n");
456     return MMSYSERR_ERROR; 
457 }
458
459 static  DWORD   widStop(WAVEMAPDATA* wim)
460 {
461     return waveInStop(wim->hWave);
462 }
463
464 static  DWORD   widStart(WAVEMAPDATA* wim)
465 {
466     return waveInStart(wim->hWave);
467 }
468
469 static  DWORD   widReset(WAVEMAPDATA* wim)
470 {
471     return waveInReset(wim->hWave);
472 }
473
474 /**************************************************************************
475  *                              WAVEMAP_widMessage      [sample driver]
476  */
477 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
478                                 DWORD dwParam1, DWORD dwParam2)
479 {
480     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
481           wDevID, wMsg, dwUser, dwParam1, dwParam2);
482
483     switch (wMsg) {
484     case DRVM_INIT:
485     case DRVM_EXIT:
486     case DRVM_ENABLE:
487     case DRVM_DISABLE:
488         /* FIXME: Pretend this is supported */
489         return 0;
490
491     case WIDM_OPEN:             return widOpen          ((LPDWORD)dwUser,     (LPWAVEOPENDESC)dwParam1, dwParam2);
492     case WIDM_CLOSE:            return widClose         ((WAVEMAPDATA*)dwUser);
493
494     case WIDM_ADDBUFFER:        return widAddBuffer     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
495     case WIDM_PREPARE:          return widPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
496     case WIDM_UNPREPARE:        return widUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
497     case WIDM_GETDEVCAPS:       return widGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSA)dwParam1, dwParam2);
498     case WIDM_GETNUMDEVS:       return 1;
499     case WIDM_GETPOS:           return widGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,      dwParam2);
500     case WIDM_RESET:            return widReset         ((WAVEMAPDATA*)dwUser);
501     case WIDM_START:            return widStart         ((WAVEMAPDATA*)dwUser);
502     case WIDM_STOP:             return widStop          ((WAVEMAPDATA*)dwUser);
503     default:
504         FIXME("unknown message %u!\n", wMsg);
505     }
506     return MMSYSERR_NOTSUPPORTED;
507 }
508
509 /*======================================================================*
510  *                  Driver part                                         *
511  *======================================================================*/
512
513 static  struct WINE_WAVEMAP* oss = NULL;
514
515 /**************************************************************************
516  *                              WAVEMAP_drvOpen                 [internal]      
517  */
518 static  DWORD   WAVEMAP_drvOpen(LPSTR str)
519 {
520     if (oss)
521         return 0;
522     
523     /* I know, this is ugly, but who cares... */
524     oss = (struct WINE_WAVEMAP*)1;
525     return 1;
526 }
527
528 /**************************************************************************
529  *                              WAVEMAP_drvClose                [internal]      
530  */
531 static  DWORD   WAVEMAP_drvClose(DWORD dwDevID)
532 {
533     if (oss) {
534         oss = NULL;
535         return 1;
536     }
537     return 0;
538 }
539
540 /**************************************************************************
541  *                              WAVEMAP_DriverProc              [internal]
542  */
543 LONG CALLBACK   WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
544                                    DWORD dwParam1, DWORD dwParam2)
545 {
546 /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
547 /* EPP    dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
548     
549     switch(wMsg) {
550     case DRV_LOAD:              return 1;
551     case DRV_FREE:              return 1;
552     case DRV_OPEN:              return WAVEMAP_drvOpen((LPSTR)dwParam1);
553     case DRV_CLOSE:             return WAVEMAP_drvClose(dwDevID);
554     case DRV_ENABLE:            return 1;
555     case DRV_DISABLE:           return 1;
556     case DRV_QUERYCONFIGURE:    return 1;
557     case DRV_CONFIGURE:         MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "OSS Driver", MB_OK);     return 1;
558     case DRV_INSTALL:           return DRVCNF_RESTART;
559     case DRV_REMOVE:            return DRVCNF_RESTART;
560     default:
561         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
562     }
563 }
564
565