Added support for WAVE_FORMAT_QUERY flag in wodOpen.
[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 %ld %ld);\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, 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 /**************************************************************************
337  *                              WAVEMAP_wodMessage      [sample driver]
338  */
339 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 
340                                 DWORD dwParam1, DWORD dwParam2)
341 {
342     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
343           wDevID, wMsg, dwUser, dwParam1, dwParam2);
344     
345     switch (wMsg) {
346     case DRVM_INIT:
347     case DRVM_EXIT:
348     case DRVM_ENABLE:
349     case DRVM_DISABLE:
350         /* FIXME: Pretend this is supported */
351         return 0;
352     case WODM_OPEN:             return wodOpen          ((LPDWORD)dwUser,      (LPWAVEOPENDESC)dwParam1,dwParam2);
353     case WODM_CLOSE:            return wodClose         ((WAVEMAPDATA*)dwUser);
354     case WODM_WRITE:            return wodWrite         ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
355     case WODM_PAUSE:            return wodPause         ((WAVEMAPDATA*)dwUser);
356     case WODM_GETPOS:           return wodGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,      dwParam2);
357     case WODM_BREAKLOOP:        return MMSYSERR_NOTSUPPORTED;
358     case WODM_PREPARE:          return wodPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
359     case WODM_UNPREPARE:        return wodUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
360     case WODM_GETDEVCAPS:       return wodGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSA)dwParam1,dwParam2);
361     case WODM_GETNUMDEVS:       return 1;
362     case WODM_GETPITCH:         return MMSYSERR_NOTSUPPORTED;
363     case WODM_SETPITCH:         return MMSYSERR_NOTSUPPORTED;
364     case WODM_GETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
365     case WODM_SETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
366     case WODM_GETVOLUME:        return wodGetVolume     (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
367     case WODM_SETVOLUME:        return wodSetVolume     (wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
368     case WODM_RESTART:          return wodRestart       ((WAVEMAPDATA*)dwUser);
369     case WODM_RESET:            return wodReset         ((WAVEMAPDATA*)dwUser);
370     default:
371         FIXME("unknown message %d!\n", wMsg);
372     }
373     return MMSYSERR_NOTSUPPORTED;
374 }
375
376 /*======================================================================*
377  *                  WAVE IN part                                        *
378  *======================================================================*/
379
380 static  DWORD   widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
381 {
382     UINT                nd = waveInGetNumDevs();
383     UINT                i;
384     WAVEMAPDATA*        wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
385
386     TRACE("(%p %p %08lx\n", lpdwUser, lpDesc, dwFlags);
387
388     wim->self = wim;
389
390     for (i = 0; i < nd; i++) {
391         if (waveInOpen(&wim->hWave, i, lpDesc->lpFormat, lpDesc->dwCallback, 
392                         lpDesc->dwInstance, dwFlags) == MMSYSERR_NOERROR) {
393             lpDesc->hWave = wim->hWave;
394             *lpdwUser = (DWORD)wim;
395             return MMSYSERR_NOERROR;
396         }
397     }
398     HeapFree(GetProcessHeap(), 0, wim);
399     return MMSYSERR_ALLOCATED;
400 }
401
402 static  DWORD   widClose(WAVEMAPDATA* wim)
403 {
404     DWORD ret = waveInClose(wim->hWave);
405     if (ret == MMSYSERR_NOERROR)
406         HeapFree(GetProcessHeap(), 0, wim);
407     return ret;
408 }
409
410 static  DWORD   widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdr, DWORD dwParam2)
411 {
412     return waveInAddBuffer(wim->hWave, lpWaveHdr, dwParam2);
413 }
414
415 static  DWORD   widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdr, DWORD dwParam2)
416 {
417     return waveInPrepareHeader(wim->hWave, lpWaveHdr, dwParam2);
418 }
419
420 static  DWORD   widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdr, DWORD dwParam2)
421 {
422     return waveInUnprepareHeader(wim->hWave, lpWaveHdr, dwParam2);
423 }
424
425 static  DWORD   widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
426 {
427     return waveInGetPosition(wim->hWave, lpTime, dwParam2);
428 }
429
430 static  DWORD   widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSA lpWaveCaps, DWORD dwParam2)
431 {
432     /* if opened low driver, forward message */
433     if (WAVEMAP_IsData(wim))
434         return waveInGetDevCapsA(wim->hWave, lpWaveCaps, dwParam2);
435     /* otherwise, return caps of mapper itself */
436     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
437         lpWaveCaps->wMid = 0x00FF;
438         lpWaveCaps->wPid = 0x0001;
439         lpWaveCaps->vDriverVersion = 0x0001;
440         strcpy(lpWaveCaps->szPname, "Wine wave in mapper");
441         lpWaveCaps->dwFormats = 
442             WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
443             WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
444             WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;    
445         lpWaveCaps->wChannels = 2;
446         return MMSYSERR_NOERROR;
447     }
448     ERR("This shouldn't happen\n");
449     return MMSYSERR_ERROR; 
450 }
451
452 static  DWORD   widStop(WAVEMAPDATA* wim)
453 {
454     return waveInStop(wim->hWave);
455 }
456
457 static  DWORD   widStart(WAVEMAPDATA* wim)
458 {
459     return waveInStart(wim->hWave);
460 }
461
462 static  DWORD   widReset(WAVEMAPDATA* wim)
463 {
464     return waveInReset(wim->hWave);
465 }
466
467 /**************************************************************************
468  *                              WAVEMAP_widMessage      [sample driver]
469  */
470 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
471                                 DWORD dwParam1, DWORD dwParam2)
472 {
473     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
474           wDevID, wMsg, dwUser, dwParam1, dwParam2);
475
476     switch (wMsg) {
477     case DRVM_INIT:
478     case DRVM_EXIT:
479     case DRVM_ENABLE:
480     case DRVM_DISABLE:
481         /* FIXME: Pretend this is supported */
482         return 0;
483
484     case WIDM_OPEN:             return widOpen          ((LPDWORD)dwUser,     (LPWAVEOPENDESC)dwParam1, dwParam2);
485     case WIDM_CLOSE:            return widClose         ((WAVEMAPDATA*)dwUser);
486
487     case WIDM_ADDBUFFER:        return widAddBuffer     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
488     case WIDM_PREPARE:          return widPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
489     case WIDM_UNPREPARE:        return widUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
490     case WIDM_GETDEVCAPS:       return widGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSA)dwParam1, dwParam2);
491     case WIDM_GETNUMDEVS:       return 1;
492     case WIDM_GETPOS:           return widGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,      dwParam2);
493     case WIDM_RESET:            return widReset         ((WAVEMAPDATA*)dwUser);
494     case WIDM_START:            return widStart         ((WAVEMAPDATA*)dwUser);
495     case WIDM_STOP:             return widStop          ((WAVEMAPDATA*)dwUser);
496     default:
497         FIXME("unknown message %u!\n", wMsg);
498     }
499     return MMSYSERR_NOTSUPPORTED;
500 }
501
502 /*======================================================================*
503  *                  Driver part                                         *
504  *======================================================================*/
505
506 static  struct WINE_WAVEMAP* oss = NULL;
507
508 /**************************************************************************
509  *                              WAVEMAP_drvOpen                 [internal]      
510  */
511 static  DWORD   WAVEMAP_drvOpen(LPSTR str)
512 {
513     if (oss)
514         return 0;
515     
516     /* I know, this is ugly, but who cares... */
517     oss = (struct WINE_WAVEMAP*)1;
518     return 1;
519 }
520
521 /**************************************************************************
522  *                              WAVEMAP_drvClose                [internal]      
523  */
524 static  DWORD   WAVEMAP_drvClose(DWORD dwDevID)
525 {
526     if (oss) {
527         oss = NULL;
528         return 1;
529     }
530     return 0;
531 }
532
533 /**************************************************************************
534  *                              WAVEMAP_DriverProc              [internal]
535  */
536 LONG CALLBACK   WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
537                                    DWORD dwParam1, DWORD dwParam2)
538 {
539 /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
540 /* EPP    dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
541     
542     switch(wMsg) {
543     case DRV_LOAD:              return 1;
544     case DRV_FREE:              return 1;
545     case DRV_OPEN:              return WAVEMAP_drvOpen((LPSTR)dwParam1);
546     case DRV_CLOSE:             return WAVEMAP_drvClose(dwDevID);
547     case DRV_ENABLE:            return 1;
548     case DRV_DISABLE:           return 1;
549     case DRV_QUERYCONFIGURE:    return 1;
550     case DRV_CONFIGURE:         MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "OSS Driver", MB_OK);     return 1;
551     case DRV_INSTALL:           return DRVCNF_RESTART;
552     case DRV_REMOVE:            return DRVCNF_RESTART;
553     default:
554         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
555     }
556 }
557
558