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