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