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