Release 980118
[wine] / multimedia / audio.c
1 /*                                 
2  * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
3  *
4  * Copyright 1994 Martin Ayotte
5  */
6 /*
7  * FIXME:
8  *      - record/play should and must be done asynchronous
9  *      - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
10  */
11
12 #define EMULATE_SB16
13
14 #define DEBUG_MCIWAVE
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <sys/ioctl.h>
21 #include "windows.h"
22 #include "user.h"
23 #include "driver.h"
24 #include "mmsystem.h"
25 #include "heap.h"
26 #include "ldt.h"
27 #include "stddebug.h"
28 #include "debug.h"
29
30 #ifdef HAVE_OSS
31 #include <sys/soundcard.h>
32
33 #define SOUND_DEV "/dev/dsp"
34 #define MIXER_DEV "/dev/mixer"
35
36 #ifdef SOUND_VERSION
37 #define IOCTL(a,b,c)            ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
38 #else
39 #define IOCTL(a,b,c)            (c = ioctl(a,b,c) )
40 #endif
41
42 #define MAX_WAVOUTDRV   (1)
43 #define MAX_WAVINDRV    (1)
44 #define MAX_MCIWAVDRV   (1)
45
46 typedef struct {
47         int             unixdev;
48         int             state;
49         DWORD           bufsize;
50         WAVEOPENDESC    waveDesc;
51         WORD            wFlags;
52         PCMWAVEFORMAT   Format;
53         LPWAVEHDR       lpQueueHdr;
54         DWORD           dwTotalPlayed;
55 } LINUX_WAVEOUT;
56
57 typedef struct {
58         int             unixdev;
59         int             state;
60         DWORD           bufsize;        /* OpenSound '/dev/dsp' give us that size */
61         WAVEOPENDESC    waveDesc;
62         WORD            wFlags;
63         PCMWAVEFORMAT   Format;
64         LPWAVEHDR       lpQueueHdr;
65         DWORD           dwTotalRecorded;
66 } LINUX_WAVEIN;
67
68 typedef struct {
69         int             nUseCount;      /* Incremented for each shared open */
70         BOOL16          fShareable;     /* TRUE if first open was shareable */
71         WORD            wNotifyDeviceID;/* MCI device ID with a pending notification */
72         HANDLE16        hCallback;      /* Callback handle for pending notification */
73         HMMIO16         hFile;          /* mmio file handle open as Element */
74         MCI_WAVE_OPEN_PARMS16 openParms;
75         PCMWAVEFORMAT   WaveFormat;
76         WAVEHDR         WaveHdr;
77         BOOL16          fInput;         /* FALSE = Output, TRUE = Input */
78 } LINUX_MCIWAVE;
79
80 static LINUX_WAVEOUT    WOutDev[MAX_WAVOUTDRV];
81 static LINUX_WAVEIN     WInDev[MAX_WAVOUTDRV];
82 static LINUX_MCIWAVE    MCIWavDev[MAX_MCIWAVDRV];
83
84
85 /**************************************************************************
86  *                      WAVE_NotifyClient                       [internal]
87  */
88 static DWORD WAVE_NotifyClient(UINT16 wDevID, WORD wMsg, 
89                                 DWORD dwParam1, DWORD dwParam2)
90 {
91         dprintf_mciwave(stddeb,"WAVE_NotifyClient // wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
92
93         switch (wMsg) {
94         case WOM_OPEN:
95         case WOM_CLOSE:
96         case WOM_DONE:
97           if (wDevID > MAX_WAVOUTDRV) return MCIERR_INTERNAL;
98           
99           if (WOutDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
100                 WOutDev[wDevID].waveDesc.dwCallBack, 
101                 WOutDev[wDevID].wFlags, 
102                 WOutDev[wDevID].waveDesc.hWave, 
103                 wMsg, 
104                 WOutDev[wDevID].waveDesc.dwInstance, 
105                 dwParam1, 
106                 dwParam2)) {
107             dprintf_mciwave(stddeb,"WAVE_NotifyClient // can't notify client !\n");
108             return MMSYSERR_NOERROR;
109           }
110           break;
111
112         case WIM_OPEN:
113         case WIM_CLOSE:
114         case WIM_DATA:
115           if (wDevID > MAX_WAVINDRV) return MCIERR_INTERNAL;
116           
117           if (WInDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
118                 WInDev[wDevID].waveDesc.dwCallBack, WInDev[wDevID].wFlags, 
119                 WInDev[wDevID].waveDesc.hWave, wMsg, 
120                 WInDev[wDevID].waveDesc.dwInstance, dwParam1, dwParam2)) {
121             dprintf_mciwave(stddeb,"WAVE_NotifyClient // can't notify client !\n");
122             return MMSYSERR_NOERROR;
123           }
124           break;
125         }
126         return 0;
127 }
128
129
130 /**************************************************************************
131  *                      WAVE_mciOpen                            [internal]
132  */
133 static DWORD WAVE_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMS16 lpParms)
134 {
135         LPPCMWAVEFORMAT lpWaveFormat;
136         WAVEOPENDESC    waveDesc;
137         LPSTR           lpstrElementName;
138         DWORD           dwRet;
139         char            str[128];
140
141         dprintf_mciwave(stddeb,"WAVE_mciOpen(%04X, %08lX, %p)\n", 
142                                 wDevID, dwFlags, lpParms);
143         if (lpParms == NULL) return MCIERR_INTERNAL;
144
145         if (MCIWavDev[wDevID].nUseCount > 0) {
146                 /* The driver already open on this channel */
147                 /* If the driver was opened shareable before and this open specifies */
148                 /* shareable then increment the use count */
149                 if (MCIWavDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
150                         ++MCIWavDev[wDevID].nUseCount;
151                 else
152                         return MCIERR_MUST_USE_SHAREABLE;
153         } else {
154                 MCIWavDev[wDevID].nUseCount = 1;
155                 MCIWavDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
156         }
157
158         MCIWavDev[wDevID].fInput = FALSE;
159
160         dprintf_mciwave(stddeb,"WAVE_mciOpen // wDevID=%04X\n", wDevID);
161         dprintf_mciwave(stddeb,"WAVE_mciOpen // before OPEN_ELEMENT\n");
162         if (dwFlags & MCI_OPEN_ELEMENT) {
163                 lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(lpParms->lpstrElementName);
164                 dprintf_mciwave(stddeb,"WAVE_mciOpen // MCI_OPEN_ELEMENT '%s' !\n",
165                                                 lpstrElementName);
166                 if ( lpstrElementName && (strlen(lpstrElementName) > 0)) {
167                         strcpy(str, lpstrElementName);
168                         CharUpper32A(str);
169                         MCIWavDev[wDevID].hFile = mmioOpen16(str, NULL, 
170                                 MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
171                         if (MCIWavDev[wDevID].hFile == 0) {
172                                 dprintf_mciwave(stddeb,"WAVE_mciOpen // can't find file='%s' !\n", str);
173                                 return MCIERR_FILE_NOT_FOUND;
174                         }
175                 }
176                 else 
177                         MCIWavDev[wDevID].hFile = 0;
178         }
179         dprintf_mciwave(stddeb,"WAVE_mciOpen // hFile=%u\n", MCIWavDev[wDevID].hFile);
180         memcpy(&MCIWavDev[wDevID].openParms, lpParms, sizeof(MCI_WAVE_OPEN_PARMS16));
181         MCIWavDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
182         lpWaveFormat = &MCIWavDev[wDevID].WaveFormat;
183
184         waveDesc.hWave = 0;
185 /*
186         lpWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM;
187         lpWaveFormat->wBitsPerSample = 8;
188         lpWaveFormat->wf.nChannels = 1;
189         lpWaveFormat->wf.nSamplesPerSec = 11025;
190         lpWaveFormat->wf.nAvgBytesPerSec = 11025;
191         lpWaveFormat->wf.nBlockAlign = 1;
192 */
193         if (MCIWavDev[wDevID].hFile != 0) {
194                 MMCKINFO        mmckInfo;
195                 MMCKINFO        ckMainRIFF;
196                 if (mmioDescend(MCIWavDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0)
197                         return MCIERR_INTERNAL;
198                 dprintf_mciwave(stddeb,
199                                 "WAVE_mciOpen // ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
200                                 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
201                                 ckMainRIFF.cksize);
202                 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
203                     (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
204                         return MCIERR_INTERNAL;
205                 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
206                 if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0)
207                         return MCIERR_INTERNAL;
208                 dprintf_mciwave(stddeb,
209                                 "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
210                                 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
211                                 mmckInfo.cksize);
212                 if (mmioRead(MCIWavDev[wDevID].hFile, (HPSTR) lpWaveFormat,
213                     (long) sizeof(PCMWAVEFORMAT)) != (long) sizeof(PCMWAVEFORMAT))
214                         return MCIERR_INTERNAL;
215                 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
216                 if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0)
217                         return MCIERR_INTERNAL;
218                 dprintf_mciwave(stddeb,
219                                 "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
220                                 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
221                                 mmckInfo.cksize);
222                 dprintf_mciwave(stddeb,
223                         "WAVE_mciOpen // nChannels=%d nSamplesPerSec=%ld\n",
224                         lpWaveFormat->wf.nChannels, lpWaveFormat->wf.nSamplesPerSec);
225                 lpWaveFormat->wBitsPerSample = 0;
226         }
227         lpWaveFormat->wf.nAvgBytesPerSec = 
228                 lpWaveFormat->wf.nSamplesPerSec * lpWaveFormat->wf.nBlockAlign;
229         waveDesc.lpFormat = (LPWAVEFORMAT)lpWaveFormat;
230
231 /*
232    By default the device will be opened for output, the MCI_CUE function is there to
233    change from output to input and back
234 */
235
236         dwRet=wodMessage(wDevID,WODM_OPEN,0,(DWORD)&waveDesc,CALLBACK_NULL);
237         return 0;
238 }
239
240 /**************************************************************************
241  *                               WAVE_mciCue             [internal]
242  */
243
244 static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
245 {
246 /*
247    FIXME
248
249    This routine is far from complete. At the moment only a check is done on the
250    MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
251    is the default.
252
253    The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
254    are ignored
255 */
256
257         DWORD           dwRet;
258         WAVEOPENDESC    waveDesc;
259
260         dprintf_mciwave(stddeb,"WAVE_mciCue(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
261
262 /* always close elements ? */
263
264         if (MCIWavDev[wDevID].hFile != 0) {
265           mmioClose(MCIWavDev[wDevID].hFile, 0);
266           MCIWavDev[wDevID].hFile = 0;
267         }
268
269         dwRet = MMSYSERR_NOERROR;  /* assume success */
270         if ((dwParam & MCI_WAVE_INPUT) && !MCIWavDev[wDevID].fInput) {
271 /* FIXME this is just a hack WOutDev should be hidden here */
272                 memcpy(&waveDesc,&WOutDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
273
274                 dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
275                 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
276                 dwRet = widMessage(wDevID, WIDM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
277                 MCIWavDev[wDevID].fInput = TRUE;
278         }
279         else if (MCIWavDev[wDevID].fInput) {
280 /* FIXME this is just a hack WInDev should be hidden here */
281                 memcpy(&waveDesc,&WInDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
282
283                 dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
284                 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
285                 dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
286                 MCIWavDev[wDevID].fInput = FALSE;
287         }
288         return dwRet;
289 }
290
291 /**************************************************************************
292  *                              WAVE_mciClose           [internal]
293  */
294 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
295 {
296         DWORD           dwRet;
297
298         dprintf_mciwave(stddeb,
299                         "WAVE_mciClose(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
300         MCIWavDev[wDevID].nUseCount--;
301         if (MCIWavDev[wDevID].nUseCount == 0) {
302                 if (MCIWavDev[wDevID].hFile != 0) {
303                         mmioClose(MCIWavDev[wDevID].hFile, 0);
304                         MCIWavDev[wDevID].hFile = 0;
305                 }
306                 if (MCIWavDev[wDevID].fInput)
307                         dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
308                 else
309                         dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
310           
311                 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
312         }
313         return 0;
314 }
315
316
317 /**************************************************************************
318  *                              WAVE_mciPlay            [internal]
319  */
320 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
321 {
322         int             start, end;
323         LONG            bufsize, count;
324         HGLOBAL16       hData;
325         LPWAVEHDR       lpWaveHdr;
326         DWORD           dwRet;
327
328         dprintf_mciwave(stddeb,
329                  "WAVE_mciPlay(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
330
331         if (MCIWavDev[wDevID].fInput) {
332                 dprintf_mciwave(stddeb,"WAVE_mciPlay // cannot play on input device\n");
333                 return MCIERR_NONAPPLICABLE_FUNCTION;
334         }
335
336         if (MCIWavDev[wDevID].hFile == 0) {
337                 dprintf_mciwave(stddeb,"WAVE_mciPlay // can't find file='%08lx' !\n",
338                         MCIWavDev[wDevID].openParms.lpstrElementName);
339                 return MCIERR_FILE_NOT_FOUND;
340         }
341         start = 1;              end = 99999;
342         if (dwFlags & MCI_FROM) {
343                 start = lpParms->dwFrom; 
344                 dprintf_mciwave(stddeb,
345                                 "WAVE_mciPlay // MCI_FROM=%d \n", start);
346         }
347         if (dwFlags & MCI_TO) {
348                 end = lpParms->dwTo;
349                 dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_TO=%d \n", end);
350         }
351 #if 0
352         if (dwFlags & MCI_NOTIFY) {
353         dprintf_mciwave(stddeb,
354                 "WAVE_mciPlay // MCI_NOTIFY %08lX !\n", lpParms->dwCallback);
355                 switch(fork()) {
356                         case -1:
357                                 dprintf_mciwave(stddeb,
358                                   "WAVE_mciPlay // Can't 'fork' process !\n");
359                                 break;
360                         case 0:
361                                 break;         
362                         default:
363                                 dprintf_mciwave(stddeb,"WAVE_mciPlay // process started ! return to caller...\n");
364                                 return 0;
365                         }
366                 }
367 #endif
368         bufsize = 64000;
369         lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
370         hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
371         lpWaveHdr->lpData = (LPSTR) GlobalLock16(hData);
372         lpWaveHdr->dwUser = 0L;
373         lpWaveHdr->dwFlags = 0L;
374         lpWaveHdr->dwLoops = 0L;
375         dwRet=wodMessage(wDevID,WODM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
376         while(TRUE) {
377                 count = mmioRead(MCIWavDev[wDevID].hFile, lpWaveHdr->lpData, bufsize);
378                 dprintf_mciwave(stddeb,"WAVE_mciPlay // mmioRead bufsize=%ld count=%ld\n", bufsize, count);
379                 if (count < 1) break;
380                 lpWaveHdr->dwBufferLength = count;
381 /*              lpWaveHdr->dwBytesRecorded = count; */
382                 dprintf_mciwave(stddeb,"WAVE_mciPlay // before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
383                                 lpWaveHdr, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded);
384                 dwRet=wodMessage(wDevID,WODM_WRITE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
385         }
386         dwRet = wodMessage(wDevID,WODM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
387         if (lpWaveHdr->lpData != NULL) {
388                 GlobalUnlock16(hData);
389                 GlobalFree16(hData);
390                 lpWaveHdr->lpData = NULL;
391         }
392         if (dwFlags & MCI_NOTIFY) {
393                 dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
394                 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
395                         MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
396         }
397         return 0;
398 }
399
400
401 /**************************************************************************
402  *                              WAVE_mciRecord                  [internal]
403  */
404 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
405 {
406         int                     start, end;
407         LONG                    bufsize;
408         HGLOBAL16               hData;
409         LPWAVEHDR               lpWaveHdr;
410         DWORD                   dwRet;
411
412         dprintf_mciwave(stddeb,
413                 "WAVE_mciRecord(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
414
415         if (!MCIWavDev[wDevID].fInput) {
416                 dprintf_mciwave(stddeb,"WAVE_mciPlay // cannot record on output device\n");
417                 return MCIERR_NONAPPLICABLE_FUNCTION;
418         }
419
420         if (MCIWavDev[wDevID].hFile == 0) {
421                 dprintf_mciwave(stddeb,"WAVE_mciRecord // can't find file='%08lx' !\n", 
422                                 MCIWavDev[wDevID].openParms.lpstrElementName);
423                 return MCIERR_FILE_NOT_FOUND;
424         }
425         start = 1;      end = 99999;
426         if (dwFlags & MCI_FROM) {
427                 start = lpParms->dwFrom; 
428                 dprintf_mciwave(stddeb,
429                                 "WAVE_mciRecord // MCI_FROM=%d \n", start);
430         }
431         if (dwFlags & MCI_TO) {
432                 end = lpParms->dwTo;
433                 dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_TO=%d \n", end);
434         }
435         bufsize = 64000;
436         lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
437         hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
438         lpWaveHdr->lpData = (LPSTR)GlobalLock16(hData);
439         lpWaveHdr->dwBufferLength = bufsize;
440         lpWaveHdr->dwUser = 0L;
441         lpWaveHdr->dwFlags = 0L;
442         lpWaveHdr->dwLoops = 0L;
443         dwRet=widMessage(wDevID,WIDM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
444         dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_PREPARE \n");
445         while(TRUE) {
446                 lpWaveHdr->dwBytesRecorded = 0;
447                 dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
448                 dprintf_mciwave(stddeb,
449                     "WAVE_mciRecord // after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
450                                         lpWaveHdr, lpWaveHdr->dwBytesRecorded);
451                 if (lpWaveHdr->dwBytesRecorded == 0) break;
452         }
453         dprintf_mciwave(stddeb,"WAVE_mciRecord // before WIDM_UNPREPARE \n");
454         dwRet = widMessage(wDevID,WIDM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
455         dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_UNPREPARE \n");
456         if (lpWaveHdr->lpData != NULL) {
457                 GlobalUnlock16(hData);
458                 GlobalFree16(hData);
459                 lpWaveHdr->lpData = NULL;
460         }
461         if (dwFlags & MCI_NOTIFY) {
462           dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
463                 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
464                         MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
465         }
466         return 0;
467 }
468
469
470 /**************************************************************************
471  *                              WAVE_mciStop                    [internal]
472  */
473 static DWORD WAVE_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
474 {
475         DWORD dwRet;
476
477         dprintf_mciwave(stddeb,
478                 "WAVE_mciStop(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
479         if (lpParms == NULL) return MCIERR_INTERNAL;
480         if (MCIWavDev[wDevID].fInput)
481           dwRet = widMessage(wDevID, WIDM_STOP, 0, dwFlags, (DWORD)lpParms);
482         else
483           dwRet = wodMessage(wDevID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
484           
485         return dwRet;
486 }
487
488
489 /**************************************************************************
490  *                              WAVE_mciPause                   [internal]
491  */
492 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
493 {
494         DWORD dwRet;
495
496         dprintf_mciwave(stddeb,
497                 "WAVE_mciPause(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
498         if (lpParms == NULL) return MCIERR_INTERNAL;
499         if (MCIWavDev[wDevID].fInput)
500           dwRet = widMessage(wDevID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
501         else
502           dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
503
504         return dwRet;
505 }
506
507
508 /**************************************************************************
509  *                              WAVE_mciResume                  [internal]
510  */
511 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
512 {
513         dprintf_mciwave(stddeb,
514                 "WAVE_mciResume(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
515         if (lpParms == NULL) return MCIERR_INTERNAL;
516         return 0;
517 }
518
519
520 /**************************************************************************
521  *                              WAVE_mciSet                     [internal]
522  */
523 static DWORD WAVE_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
524 {
525         dprintf_mciwave(stddeb,
526                 "WAVE_mciSet(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
527         if (lpParms == NULL) return MCIERR_INTERNAL;
528         dprintf_mciwave(stddeb,
529                  "WAVE_mciSet // dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
530         dprintf_mciwave(stddeb,
531                  "WAVE_mciSet // dwAudio=%08lX\n", lpParms->dwAudio);
532         if (dwFlags & MCI_SET_TIME_FORMAT) {
533                 switch (lpParms->dwTimeFormat) {
534                 case MCI_FORMAT_MILLISECONDS:
535                         dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_MILLISECONDS !\n");
536                         break;
537                 case MCI_FORMAT_BYTES:
538                         dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_BYTES !\n");
539                         break;
540                 case MCI_FORMAT_SAMPLES:
541                         dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_SAMPLES !\n");
542                         break;
543                 default:
544                         dprintf_mciwave(stddeb, "WAVE_mciSet // bad time format !\n");
545                         return MCIERR_BAD_TIME_FORMAT;
546                 }
547         }
548         if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
549         if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION;
550         if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION;
551         if (dwFlags & MCI_SET_AUDIO) 
552           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO !\n");
553         if (dwFlags && MCI_SET_ON) {
554           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_ON !\n");
555           if (dwFlags && MCI_SET_AUDIO_LEFT) 
556             dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_LEFT !\n");
557           if (dwFlags && MCI_SET_AUDIO_RIGHT) 
558             dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_RIGHT !\n");
559         }
560         if (dwFlags & MCI_SET_OFF) 
561           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_OFF !\n");
562         if (dwFlags & MCI_WAVE_INPUT) 
563           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_INPUT !\n");
564         if (dwFlags & MCI_WAVE_OUTPUT) 
565           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_OUTPUT !\n");
566         if (dwFlags & MCI_WAVE_SET_ANYINPUT) 
567           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYINPUT !\n");
568         if (dwFlags & MCI_WAVE_SET_ANYOUTPUT) 
569           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYOUTPUT !\n");
570         if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) 
571           dprintf_mciwave(stddeb,
572                           "WAVE_mciSet // MCI_WAVE_SET_AVGBYTESPERSEC !\n");
573         if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) 
574           dprintf_mciwave(stddeb,
575                           "WAVE_mciSet // MCI_WAVE_SET_BITSPERSAMPLE !\n");
576         if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) 
577           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_BLOCKALIGN !\n");
578         if (dwFlags & MCI_WAVE_SET_CHANNELS) 
579           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_CHANNELS !\n");
580         if (dwFlags & MCI_WAVE_SET_FORMATTAG) 
581           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_FORMATTAG !\n");
582         if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) 
583           dprintf_mciwave(stddeb,
584                           "WAVE_mciSet // MCI_WAVE_SET_SAMPLESPERSEC !\n");
585         return 0;
586 }
587
588
589 /**************************************************************************
590  *                              WAVE_mciStatus          [internal]
591  */
592 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
593 {
594         dprintf_mciwave(stddeb,
595                 "WAVE_mciStatus(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
596         if (lpParms == NULL) return MCIERR_INTERNAL;
597         if (dwFlags & MCI_STATUS_ITEM) {
598                 switch(lpParms->dwItem) {
599                 case MCI_STATUS_CURRENT_TRACK:
600                         lpParms->dwReturn = 1;
601                         break;
602                 case MCI_STATUS_LENGTH:
603                         lpParms->dwReturn = 5555;
604                         if (dwFlags & MCI_TRACK) {
605                                 lpParms->dwTrack = 1;
606                                 lpParms->dwReturn = 2222;
607                                 }
608                         break;
609                 case MCI_STATUS_MODE:
610                         lpParms->dwReturn = MCI_MODE_STOP;
611                         break;
612                 case MCI_STATUS_MEDIA_PRESENT:
613                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_MEDIA_PRESENT !\n");
614                         lpParms->dwReturn = TRUE;
615                         break;
616                 case MCI_STATUS_NUMBER_OF_TRACKS:
617                         lpParms->dwReturn = 1;
618                         break;
619                 case MCI_STATUS_POSITION:
620                         lpParms->dwReturn = 3333;
621                         if (dwFlags & MCI_STATUS_START)
622                                 lpParms->dwItem = 1;
623                         if (dwFlags & MCI_TRACK) {
624                                 lpParms->dwTrack = 1;
625                                 lpParms->dwReturn = 777;
626                         }
627                         break;
628                 case MCI_STATUS_READY:
629                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_READY !\n");
630                         lpParms->dwReturn = TRUE;
631                         break;
632                 case MCI_STATUS_TIME_FORMAT:
633                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_TIME_FORMAT !\n");
634                         lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
635                         break;
636                 case MCI_WAVE_INPUT:
637                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_INPUT !\n");
638                         lpParms->dwReturn = 0;
639                         break;
640                 case MCI_WAVE_OUTPUT:
641                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_OUTPUT !\n");
642                         lpParms->dwReturn = 0;
643                         break;
644                 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
645                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_AVGBYTESPERSEC !\n");
646                         lpParms->dwReturn = 22050;
647                         break;
648                 case MCI_WAVE_STATUS_BITSPERSAMPLE:
649                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BITSPERSAMPLE !\n");
650                         lpParms->dwReturn = 8;
651                         break;
652                 case MCI_WAVE_STATUS_BLOCKALIGN:
653                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BLOCKALIGN !\n");
654                         lpParms->dwReturn = 1;
655                         break;
656                 case MCI_WAVE_STATUS_CHANNELS:
657                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_CHANNELS !\n");
658                         lpParms->dwReturn = 1;
659                         break;
660                 case MCI_WAVE_STATUS_FORMATTAG:
661                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_FORMATTAG !\n");
662                         lpParms->dwReturn = WAVE_FORMAT_PCM;
663                         break;
664                 case MCI_WAVE_STATUS_LEVEL:
665                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_LEVEL !\n");
666                         lpParms->dwReturn = 0xAAAA5555;
667                         break;
668                 case MCI_WAVE_STATUS_SAMPLESPERSEC:
669                         dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_SAMPLESPERSEC !\n");
670                         lpParms->dwReturn = 22050;
671                         break;
672                 default:
673                         dprintf_mciwave(stddeb,"WAVE_mciStatus // unknown command %08lX !\n", lpParms->dwItem);
674                         return MCIERR_UNRECOGNIZED_COMMAND;
675                 }
676         }
677         if (dwFlags & MCI_NOTIFY) {
678                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
679                 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
680                         MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
681         }
682         return 0;
683 }
684
685 /**************************************************************************
686  *                              WAVE_mciGetDevCaps              [internal]
687  */
688 static DWORD WAVE_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags, 
689                                         LPMCI_GETDEVCAPS_PARMS lpParms)
690 {
691         dprintf_mciwave(stddeb,
692                 "WAVE_mciGetDevCaps(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
693         if (lpParms == NULL) return MCIERR_INTERNAL;
694         if (dwFlags & MCI_GETDEVCAPS_ITEM) {
695                 switch(lpParms->dwItem) {
696                 case MCI_GETDEVCAPS_CAN_RECORD:
697                         lpParms->dwReturn = TRUE;
698                         break;
699                 case MCI_GETDEVCAPS_HAS_AUDIO:
700                         lpParms->dwReturn = TRUE;
701                         break;
702                 case MCI_GETDEVCAPS_HAS_VIDEO:
703                         lpParms->dwReturn = FALSE;
704                         break;
705                 case MCI_GETDEVCAPS_DEVICE_TYPE:
706                         lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
707                         break;
708                 case MCI_GETDEVCAPS_USES_FILES:
709                         lpParms->dwReturn = TRUE;
710                         break;
711                 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
712                         lpParms->dwReturn = TRUE;
713                         break;
714                 case MCI_GETDEVCAPS_CAN_EJECT:
715                         lpParms->dwReturn = FALSE;
716                         break;
717                 case MCI_GETDEVCAPS_CAN_PLAY:
718                         lpParms->dwReturn = TRUE;
719                         break;
720                 case MCI_GETDEVCAPS_CAN_SAVE:
721                         lpParms->dwReturn = TRUE;
722                         break;
723                 case MCI_WAVE_GETDEVCAPS_INPUTS:
724                         lpParms->dwReturn = 1;
725                         break;
726                 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
727                         lpParms->dwReturn = 1;
728                         break;
729                 default:
730                         return MCIERR_UNRECOGNIZED_COMMAND;
731                 }
732         }
733         return 0;
734 }
735
736 /**************************************************************************
737  *                              WAVE_mciInfo                    [internal]
738  */
739 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
740 {
741         dprintf_mciwave(stddeb,
742                 "WAVE_mciInfo(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
743         if (lpParms == NULL) return MCIERR_INTERNAL;
744         lpParms->lpstrReturn = NULL;
745         switch(dwFlags) {
746         case MCI_INFO_PRODUCT:
747                 lpParms->lpstrReturn = "Open Sound System 0.5";
748                 break;
749         case MCI_INFO_FILE:
750                 lpParms->lpstrReturn = 
751                         (LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName;
752                 break;
753         case MCI_WAVE_INPUT:
754                 lpParms->lpstrReturn = "Open Sound System 0.5";
755                 break;
756         case MCI_WAVE_OUTPUT:
757                 lpParms->lpstrReturn = "Open Sound System 0.5";
758                 break;
759         default:
760                 return MCIERR_UNRECOGNIZED_COMMAND;
761         }
762         if (lpParms->lpstrReturn != NULL)
763                 lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
764         else
765                 lpParms->dwRetSize = 0;
766         return 0;
767 }
768
769
770 /*-----------------------------------------------------------------------*/
771
772
773 /**************************************************************************
774  *                      wodGetDevCaps                           [internal]
775  */
776 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS16 lpCaps, DWORD dwSize)
777 {
778         int     audio;
779         int     smplrate;
780         int     samplesize = 16;
781         int     dsp_stereo = 1;
782         int     bytespersmpl;
783
784         dprintf_mciwave(stddeb,
785                    "wodGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
786         if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
787         if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
788         audio = open (SOUND_DEV, O_WRONLY, 0);
789         if (audio == -1) return MMSYSERR_ALLOCATED ;
790 #ifdef EMULATE_SB16
791         lpCaps->wMid = 0x0002;
792         lpCaps->wPid = 0x0104;
793         strcpy(lpCaps->szPname, "SB16 Wave Out");
794 #else
795         lpCaps->wMid = 0x00FF;  /* Manufac ID */
796         lpCaps->wPid = 0x0001;  /* Product ID */
797         strcpy(lpCaps->szPname, "OpenSoundSystem WAVOUT Driver");
798 #endif
799         lpCaps->vDriverVersion = 0x0100;
800         lpCaps->dwFormats = 0x00000000;
801         lpCaps->dwSupport = WAVECAPS_VOLUME;
802         lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
803         if (lpCaps->wChannels > 1) lpCaps->dwSupport |= WAVECAPS_LRVOLUME;
804         bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
805         smplrate = 44100;
806         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
807                 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
808                 if (lpCaps->wChannels > 1)
809                         lpCaps->dwFormats |= WAVE_FORMAT_4S08;
810                 if (bytespersmpl > 1) {
811                         lpCaps->dwFormats |= WAVE_FORMAT_4M16;
812                         if (lpCaps->wChannels > 1)
813                                 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
814                 }
815         }
816         smplrate = 22050;
817         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
818                 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
819                 if (lpCaps->wChannels > 1)
820                         lpCaps->dwFormats |= WAVE_FORMAT_2S08;
821                 if (bytespersmpl > 1) {
822                         lpCaps->dwFormats |= WAVE_FORMAT_2M16;
823                         if (lpCaps->wChannels > 1)
824                                 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
825                 }
826         }
827         smplrate = 11025;
828         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
829                 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
830                 if (lpCaps->wChannels > 1)
831                         lpCaps->dwFormats |= WAVE_FORMAT_1S08;
832                 if (bytespersmpl > 1) {
833                         lpCaps->dwFormats |= WAVE_FORMAT_1M16;
834                         if (lpCaps->wChannels > 1)
835                                 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
836                 }
837         }
838         close(audio);
839         dprintf_mciwave(stddeb,
840                 "wodGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats);
841         return MMSYSERR_NOERROR;
842 }
843
844
845 /**************************************************************************
846  *                              wodOpen                         [internal]
847  */
848 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
849 {
850         int      audio,abuf_size,smplrate,samplesize,dsp_stereo;
851         LPWAVEFORMAT    lpFormat;
852
853         dprintf_mciwave(stddeb,
854                 "wodOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
855         if (lpDesc == NULL) {
856                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Invalid Parameter !\n");
857                 return MMSYSERR_INVALPARAM;
858         }
859         if (wDevID >= MAX_WAVOUTDRV) {
860                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // MAX_WAVOUTDRV reached !\n");
861                 return MMSYSERR_ALLOCATED;
862         }
863         WOutDev[wDevID].unixdev = 0;
864         if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
865         audio = open (SOUND_DEV, O_WRONLY, 0);
866         if (audio == -1) {
867                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't open !\n");
868                 return MMSYSERR_ALLOCATED ;
869         }
870         IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
871         if (abuf_size < 1024 || abuf_size > 65536) {
872                 if (abuf_size == -1)
873                         dprintf_mciwave(stddeb,"Linux 'wodOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
874                 else
875                         dprintf_mciwave(stddeb,"Linux 'wodOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
876                 return MMSYSERR_NOTENABLED;
877         }
878         WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
879         switch(WOutDev[wDevID].wFlags) {
880         case DCB_NULL:
881                 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_NULL !\n");
882                 break;
883         case DCB_WINDOW:
884                 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_WINDOW !\n");
885                 break;
886         case DCB_TASK:
887                 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_TASK !\n");
888                 break;
889         case DCB_FUNCTION:
890                 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_FUNCTION !\n");
891                 break;
892         }
893         WOutDev[wDevID].lpQueueHdr = NULL;
894         WOutDev[wDevID].unixdev = audio;
895         WOutDev[wDevID].dwTotalPlayed = 0;
896         WOutDev[wDevID].bufsize = abuf_size;
897         /* FIXME: copy lpFormat too? */
898         memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
899         dprintf_mciwave(stddeb,"Linux 'wodOpen' // lpDesc->lpFormat = %p\n",lpDesc->lpFormat);
900         lpFormat = lpDesc->lpFormat; 
901         dprintf_mciwave(stddeb,"Linux 'wodOpen' // lpFormat = %p\n",lpFormat);
902         if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
903                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad format %04X !\n",
904                                 lpFormat->wFormatTag);
905                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nChannels %d !\n",
906                                 lpFormat->nChannels);
907                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nSamplesPerSec %ld !\n",
908                                 lpFormat->nSamplesPerSec);
909                 return WAVERR_BADFORMAT;
910         }
911         memcpy(&WOutDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
912         if (WOutDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
913         if (WOutDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
914         dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n",
915                                 WOutDev[wDevID].Format.wBitsPerSample);
916         if (WOutDev[wDevID].Format.wBitsPerSample == 0) {
917                 WOutDev[wDevID].Format.wBitsPerSample = 8 *
918                 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec /
919                 WOutDev[wDevID].Format.wf.nSamplesPerSec) /
920                 WOutDev[wDevID].Format.wf.nChannels;
921         }
922         samplesize = WOutDev[wDevID].Format.wBitsPerSample;
923         smplrate = WOutDev[wDevID].Format.wf.nSamplesPerSec;
924         dsp_stereo = (WOutDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
925         IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
926         IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
927         IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
928         dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n",
929                                 WOutDev[wDevID].Format.wBitsPerSample);
930         dprintf_mciwave(stddeb,"Linux 'wodOpen' // nAvgBytesPerSec=%lu !\n",
931                                 WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
932         dprintf_mciwave(stddeb,"Linux 'wodOpen' // nSamplesPerSec=%lu !\n",
933                                 WOutDev[wDevID].Format.wf.nSamplesPerSec);
934         dprintf_mciwave(stddeb,"Linux 'wodOpen' // nChannels=%u !\n",
935                                 WOutDev[wDevID].Format.wf.nChannels);
936         if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
937                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't notify client !\n");
938                 return MMSYSERR_INVALPARAM;
939         }
940         return MMSYSERR_NOERROR;
941 }
942
943 /**************************************************************************
944  *                              wodClose                        [internal]
945  */
946 static DWORD wodClose(WORD wDevID)
947 {
948         dprintf_mciwave(stddeb,"wodClose(%u);\n", wDevID);
949         if (wDevID > MAX_WAVOUTDRV) return MMSYSERR_INVALPARAM;
950         if (WOutDev[wDevID].unixdev == 0) {
951                 dprintf_mciwave(stddeb,"Linux 'wodClose' // can't close !\n");
952                 return MMSYSERR_NOTENABLED;
953         }
954         if (WOutDev[wDevID].lpQueueHdr != NULL) {
955                 dprintf_mciwave(stddeb,"linux 'wodclose' // still buffers open !\n");
956                 /* Don't care. Who needs those buffers anyway */
957                 /*return WAVERR_STILLPLAYING; */
958         }
959         close(WOutDev[wDevID].unixdev);
960         WOutDev[wDevID].unixdev = 0;
961         WOutDev[wDevID].bufsize = 0;
962         WOutDev[wDevID].lpQueueHdr = NULL;
963         if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
964                 dprintf_mciwave(stddeb,"Linux 'wodClose' // can't notify client !\n");
965                 return MMSYSERR_INVALPARAM;
966         }
967         return MMSYSERR_NOERROR;
968 }
969
970 /**************************************************************************
971  *                              wodWrite                        [internal]
972  * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
973  * device, and initiate async playing.
974  */
975 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
976 {
977         int             count;
978         LPSTR           lpData;
979         LPWAVEHDR       xwavehdr;
980
981         dprintf_mciwave(stddeb,"wodWrite(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
982         if (WOutDev[wDevID].unixdev == 0) {
983         dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't play !\n");
984                 return MMSYSERR_NOTENABLED;
985         }
986         if (lpWaveHdr->lpData == NULL) return WAVERR_UNPREPARED;
987         if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) return WAVERR_UNPREPARED;
988         if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
989         lpWaveHdr->dwFlags &= ~WHDR_DONE;
990         lpWaveHdr->dwFlags |= WHDR_INQUEUE;
991         dprintf_mciwave(stddeb,
992                 "wodWrite() // dwBufferLength %lu !\n", lpWaveHdr->dwBufferLength);
993         dprintf_mciwave(stddeb,
994                 "wodWrite() // WOutDev[%u].unixdev %u !\n", wDevID, WOutDev[wDevID].unixdev);
995         lpData = lpWaveHdr->lpData;
996         count = write (WOutDev[wDevID].unixdev, lpData, lpWaveHdr->dwBufferLength);
997         dprintf_mciwave(stddeb,"wodWrite()//write returned count %u !\n",count);
998         if (count != lpWaveHdr->dwBufferLength) {
999                 dprintf_mciwave(stddeb,"Linux 'wodWrite' // error writting !\n");
1000                 return MMSYSERR_NOTENABLED;
1001         }
1002         WOutDev[wDevID].dwTotalPlayed += count;
1003         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1004         lpWaveHdr->dwFlags |= WHDR_DONE;
1005         if ((DWORD)lpWaveHdr->lpData!=lpWaveHdr->reserved) {
1006                 /* FIXME: what if it expects it's OWN lpwavehdr back? */
1007                 xwavehdr = SEGPTR_NEW(WAVEHDR);
1008                 memcpy(xwavehdr,lpWaveHdr,sizeof(WAVEHDR));
1009                 xwavehdr->lpData = (LPBYTE)xwavehdr->reserved;
1010                 if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)SEGPTR_GET(xwavehdr), count) != MMSYSERR_NOERROR) {
1011                         dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't notify client !\n");
1012                         SEGPTR_FREE(xwavehdr);
1013                         return MMSYSERR_INVALPARAM;
1014                 }
1015                 SEGPTR_FREE(xwavehdr);
1016         } else {
1017                 if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)lpWaveHdr, count) != MMSYSERR_NOERROR) {
1018                         dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't notify client !\n");
1019                         return MMSYSERR_INVALPARAM;
1020                 }
1021         }
1022         return MMSYSERR_NOERROR;
1023 }
1024
1025 /**************************************************************************
1026  *                              wodPrepare                      [internal]
1027  */
1028 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1029 {
1030         dprintf_mciwave(stddeb,
1031                 "wodPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1032         if (WOutDev[wDevID].unixdev == 0) {
1033                 dprintf_mciwave(stddeb,"Linux 'wodPrepare' // can't prepare !\n");
1034                 return MMSYSERR_NOTENABLED;
1035         }
1036         /* don't append to queue, wodWrite does that */
1037         WOutDev[wDevID].dwTotalPlayed = 0;
1038         if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1039                 return WAVERR_STILLPLAYING;
1040         lpWaveHdr->dwFlags |= WHDR_PREPARED;
1041         lpWaveHdr->dwFlags &= ~WHDR_DONE;
1042         return MMSYSERR_NOERROR;
1043 }
1044
1045 /**************************************************************************
1046  *                              wodUnprepare                    [internal]
1047  */
1048 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1049 {
1050         dprintf_mciwave(stddeb,
1051                 "wodUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1052         if (WOutDev[wDevID].unixdev == 0) {
1053                 dprintf_mciwave(stddeb,"Linux 'wodUnprepare' // can't unprepare !\n");
1054                 return MMSYSERR_NOTENABLED;
1055         }
1056         if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1057                 return WAVERR_STILLPLAYING;
1058         
1059         lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1060         lpWaveHdr->dwFlags |= WHDR_DONE;
1061         dprintf_mciwave(stddeb,
1062                 "Linux 'wodUnprepare' // all headers unprepared !\n");
1063         return MMSYSERR_NOERROR;
1064 }
1065
1066 /**************************************************************************
1067  *                      wodRestart                              [internal]
1068  */
1069 static DWORD wodRestart(WORD wDevID)
1070 {
1071         dprintf_mciwave(stddeb,"wodRestart(%u);\n", wDevID);
1072         if (WOutDev[wDevID].unixdev == 0) {
1073                 dprintf_mciwave(stddeb,"Linux 'wodRestart' // can't restart !\n");
1074                 return MMSYSERR_NOTENABLED;
1075         }
1076         /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
1077         if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
1078                 dprintf_mciwave(stddeb,"Linux 'wodRestart' // can't notify client !\n");
1079                 return MMSYSERR_INVALPARAM;
1080         }
1081
1082         return MMSYSERR_NOERROR;
1083 }
1084
1085 /**************************************************************************
1086  *                      wodReset                                [internal]
1087  */
1088 static DWORD wodReset(WORD wDevID)
1089 {
1090         dprintf_mciwave(stddeb,"wodReset(%u);\n", wDevID);
1091         if (WOutDev[wDevID].unixdev == 0) {
1092                 dprintf_mciwave(stddeb,"Linux 'wodReset' // can't reset !\n");
1093                 return MMSYSERR_NOTENABLED;
1094                 }
1095         return MMSYSERR_NOERROR;
1096 }
1097
1098
1099 /**************************************************************************
1100  *                              wodGetPosition                  [internal]
1101  */
1102 static DWORD wodGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
1103 {
1104         int             time;
1105         dprintf_mciwave(stddeb,"wodGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1106         if (WOutDev[wDevID].unixdev == 0) {
1107                 dprintf_mciwave(stddeb,"Linux 'wodGetPosition' // can't get pos !\n");
1108                 return MMSYSERR_NOTENABLED;
1109         }
1110         if (lpTime == NULL)     return MMSYSERR_INVALPARAM;
1111         dprintf_mciwave(stddeb,"wodGetPosition // wType=%04X !\n", 
1112                         lpTime->wType);
1113         dprintf_mciwave(stddeb,"wodGetPosition // wBitsPerSample=%u\n",
1114                         WOutDev[wDevID].Format.wBitsPerSample); 
1115         dprintf_mciwave(stddeb,"wodGetPosition // nSamplesPerSec=%lu\n",
1116                         WOutDev[wDevID].Format.wf.nSamplesPerSec); 
1117         dprintf_mciwave(stddeb,"wodGetPosition // nChannels=%u\n",
1118                         WOutDev[wDevID].Format.wf.nChannels); 
1119         dprintf_mciwave(stddeb,"wodGetPosition // nAvgBytesPerSec=%lu\n",
1120                         WOutDev[wDevID].Format.wf.nAvgBytesPerSec); 
1121         switch(lpTime->wType) {
1122         case TIME_BYTES:
1123                 lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed;
1124                 dprintf_mciwave(stddeb,"wodGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb);
1125                 break;
1126         case TIME_SAMPLES:
1127                 dprintf_mciwave(stddeb,"wodGetPosition // dwTotalPlayed=%lu\n", 
1128                                 WOutDev[wDevID].dwTotalPlayed);
1129                 dprintf_mciwave(stddeb,"wodGetPosition // wBitsPerSample=%u\n", 
1130                                 WOutDev[wDevID].Format.wBitsPerSample);
1131                 lpTime->u.sample = WOutDev[wDevID].dwTotalPlayed * 8 /
1132                                         WOutDev[wDevID].Format.wBitsPerSample;
1133                 dprintf_mciwave(stddeb,"wodGetPosition // TIME_SAMPLES=%lu\n", lpTime->u.sample);
1134                 break;
1135         case TIME_SMPTE:
1136                 time = WOutDev[wDevID].dwTotalPlayed /
1137                         (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1138                 lpTime->u.smpte.hour = time / 108000;
1139                 time -= lpTime->u.smpte.hour * 108000;
1140                 lpTime->u.smpte.min = time / 1800;
1141                 time -= lpTime->u.smpte.min * 1800;
1142                 lpTime->u.smpte.sec = time / 30;
1143                 time -= lpTime->u.smpte.sec * 30;
1144                 lpTime->u.smpte.frame = time;
1145                 lpTime->u.smpte.fps = 30;
1146                 dprintf_mciwave(stddeb,
1147                   "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1148                   lpTime->u.smpte.hour, lpTime->u.smpte.min,
1149                   lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1150                 break;
1151         default:
1152                 dprintf_mciwave(stddeb,"wodGetPosition() format not supported ! use TIME_MS !\n");
1153                 lpTime->wType = TIME_MS;
1154         case TIME_MS:
1155                 lpTime->u.ms = WOutDev[wDevID].dwTotalPlayed /
1156                                 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1157                 dprintf_mciwave(stddeb,"wodGetPosition // TIME_MS=%lu\n", lpTime->u.ms);
1158                 break;
1159         }
1160         return MMSYSERR_NOERROR;
1161 }
1162
1163 /**************************************************************************
1164  *                              wodGetVolume                    [internal]
1165  */
1166 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1167 {
1168         int     mixer;
1169         int             volume, left, right;
1170         dprintf_mciwave(stddeb,"wodGetVolume(%u, %p);\n", wDevID, lpdwVol);
1171         if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
1172         if ((mixer = open(MIXER_DEV, O_RDONLY)) < 0) {
1173                 dprintf_mciwave(stddeb, "Linux 'wodGetVolume' // mixer device not available !\n");
1174                 return MMSYSERR_NOTENABLED;
1175         }
1176         if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) {
1177                 dprintf_mciwave(stddeb,"Linux 'wodGetVolume' // unable read mixer !\n");
1178                 return MMSYSERR_NOTENABLED;
1179         }
1180         close(mixer);
1181         left = volume & 0x7F;
1182         right = (volume >> 8) & 0x7F;
1183         dprintf_mciwave(stddeb,"Linux 'wodGetVolume' // left=%d right=%d !\n", left, right);
1184         *lpdwVol = MAKELONG(left << 9, right << 9);
1185         return MMSYSERR_NOERROR;
1186 }
1187
1188
1189 /**************************************************************************
1190  *                              wodSetVolume                    [internal]
1191  */
1192 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1193 {
1194         int     mixer;
1195         int             volume;
1196         dprintf_mciwave(stddeb,"wodSetVolume(%u, %08lX);\n", wDevID, dwParam);
1197         volume = (LOWORD(dwParam) >> 9 & 0x7F) + 
1198                 ((HIWORD(dwParam) >> 9  & 0x7F) << 8);
1199         if ((mixer = open(MIXER_DEV, O_WRONLY)) < 0) {
1200                 dprintf_mciwave(stddeb, "Linux 'wodSetVolume' // mixer device not available !\n");
1201                 return MMSYSERR_NOTENABLED;
1202                 }
1203     if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) {
1204                 dprintf_mciwave(stddeb,"Linux 'wodSetVolume' // unable set mixer !\n");
1205                 return MMSYSERR_NOTENABLED;
1206                 }
1207         close(mixer);
1208         return MMSYSERR_NOERROR;
1209 }
1210
1211 /**************************************************************************
1212  *                              wodMessage                      [sample driver]
1213  */
1214 DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1215                                         DWORD dwParam1, DWORD dwParam2)
1216 {
1217         dprintf_mciwave(stddeb,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1218                         wDevID, wMsg, dwUser, dwParam1, dwParam2);
1219         switch(wMsg) {
1220         case WODM_OPEN:
1221                 return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1222         case WODM_CLOSE:
1223                 return wodClose(wDevID);
1224         case WODM_WRITE:
1225                 return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1226         case WODM_PAUSE:
1227                 return MMSYSERR_NOTSUPPORTED;
1228         case WODM_STOP:
1229                 return MMSYSERR_NOTSUPPORTED;
1230         case WODM_GETPOS:
1231                 return wodGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1232         case WODM_BREAKLOOP:
1233                 return MMSYSERR_NOTSUPPORTED;
1234         case WODM_PREPARE:
1235                 return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1236         case WODM_UNPREPARE:
1237                 return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1238         case WODM_GETDEVCAPS:
1239                 return wodGetDevCaps(wDevID,(LPWAVEOUTCAPS16)dwParam1,dwParam2);
1240         case WODM_GETNUMDEVS:
1241                 return 1L;
1242         case WODM_GETPITCH:
1243                 return MMSYSERR_NOTSUPPORTED;
1244         case WODM_SETPITCH:
1245                 return MMSYSERR_NOTSUPPORTED;
1246         case WODM_GETPLAYBACKRATE:
1247                 return MMSYSERR_NOTSUPPORTED;
1248         case WODM_SETPLAYBACKRATE:
1249                 return MMSYSERR_NOTSUPPORTED;
1250         case WODM_GETVOLUME:
1251                 return wodGetVolume(wDevID, (LPDWORD)dwParam1);
1252         case WODM_SETVOLUME:
1253                 return wodSetVolume(wDevID, dwParam1);
1254         case WODM_RESTART:
1255                 return wodRestart(wDevID);
1256         case WODM_RESET:
1257                 return wodReset(wDevID);
1258         default:
1259                 dprintf_mciwave(stddeb,"wodMessage // unknown message !\n");
1260         }
1261         return MMSYSERR_NOTSUPPORTED;
1262 }
1263
1264
1265 /*-----------------------------------------------------------------------*/
1266
1267 /**************************************************************************
1268  *                      widGetDevCaps                           [internal]
1269  */
1270 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPS16 lpCaps, DWORD dwSize)
1271 {
1272         int     audio,smplrate,samplesize=16,dsp_stereo=1,bytespersmpl;
1273
1274         dprintf_mciwave(stddeb,
1275                 "widGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
1276         if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1277         if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
1278         audio = open (SOUND_DEV, O_RDONLY, 0);
1279         if (audio == -1) return MMSYSERR_ALLOCATED ;
1280 #ifdef EMULATE_SB16
1281         lpCaps->wMid = 0x0002;
1282         lpCaps->wPid = 0x0004;
1283         strcpy(lpCaps->szPname, "SB16 Wave In");
1284 #else
1285         lpCaps->wMid = 0x00FF;  /* Manufac ID */
1286         lpCaps->wPid = 0x0001;  /* Product ID */
1287         strcpy(lpCaps->szPname, "OpenSoundSystem WAVIN Driver");
1288 #endif
1289         lpCaps->dwFormats = 0x00000000;
1290         lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
1291         bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
1292         smplrate = 44100;
1293         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1294                 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
1295                 if (lpCaps->wChannels > 1)
1296                         lpCaps->dwFormats |= WAVE_FORMAT_4S08;
1297                 if (bytespersmpl > 1) {
1298                         lpCaps->dwFormats |= WAVE_FORMAT_4M16;
1299                         if (lpCaps->wChannels > 1)
1300                                 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
1301                 }
1302         }
1303         smplrate = 22050;
1304         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1305                 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
1306                 if (lpCaps->wChannels > 1)
1307                         lpCaps->dwFormats |= WAVE_FORMAT_2S08;
1308                 if (bytespersmpl > 1) {
1309                         lpCaps->dwFormats |= WAVE_FORMAT_2M16;
1310                         if (lpCaps->wChannels > 1)
1311                                 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
1312                 }
1313         }
1314         smplrate = 11025;
1315         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1316                 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
1317                 if (lpCaps->wChannels > 1)
1318                         lpCaps->dwFormats |= WAVE_FORMAT_1S08;
1319                 if (bytespersmpl > 1) {
1320                         lpCaps->dwFormats |= WAVE_FORMAT_1M16;
1321                         if (lpCaps->wChannels > 1)
1322                                 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
1323                 }
1324         }
1325         close(audio);
1326         dprintf_mciwave(stddeb,
1327                 "widGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats);
1328         return MMSYSERR_NOERROR;
1329 }
1330
1331
1332 /**************************************************************************
1333  *                              widOpen                         [internal]
1334  */
1335 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1336 {
1337         int             audio,abuf_size,smplrate,samplesize,dsp_stereo;
1338         LPWAVEFORMAT    lpFormat;
1339
1340         dprintf_mciwave(stddeb, "widOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
1341         if (lpDesc == NULL) {
1342                 dprintf_mciwave(stddeb,"Linux 'widOpen' // Invalid Parameter !\n");
1343                 return MMSYSERR_INVALPARAM;
1344         }
1345         if (wDevID >= MAX_WAVINDRV) {
1346                 dprintf_mciwave(stddeb,"Linux 'widOpen' // MAX_WAVINDRV reached !\n");
1347                 return MMSYSERR_ALLOCATED;
1348         }
1349         WInDev[wDevID].unixdev = 0;
1350         if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
1351         audio = open (SOUND_DEV, O_RDONLY, 0);
1352         if (audio == -1) {
1353                 dprintf_mciwave(stddeb,"Linux 'widOpen' // can't open !\n");
1354                 return MMSYSERR_ALLOCATED;
1355         }
1356         IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
1357         if (abuf_size < 1024 || abuf_size > 65536) {
1358                 if (abuf_size == -1)
1359                         dprintf_mciwave(stddeb,"Linux 'widOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
1360                 else
1361                         dprintf_mciwave(stddeb,"Linux 'widOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
1362                 return MMSYSERR_NOTENABLED;
1363         }
1364         WInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1365         switch(WInDev[wDevID].wFlags) {
1366         case DCB_NULL:
1367                 dprintf_mciwave(stddeb,"Linux 'widOpen' // CALLBACK_NULL!\n");
1368                 break;
1369         case DCB_WINDOW:
1370                 dprintf_mciwave(stddeb,"Linux 'widOpen' // CALLBACK_WINDOW!\n");
1371                 break;
1372         case DCB_TASK:
1373                 dprintf_mciwave(stddeb,"Linux 'widOpen' // CALLBACK_TASK!\n");
1374                 break;
1375         case DCB_FUNCTION:
1376                 dprintf_mciwave(stddeb,"Linux 'widOpen' // CALLBACK_FUNCTION!\n");
1377                 break;
1378         }
1379         if (WInDev[wDevID].lpQueueHdr) {
1380                 HeapFree(GetProcessHeap(),0,WInDev[wDevID].lpQueueHdr);
1381                 WInDev[wDevID].lpQueueHdr = NULL;
1382         }
1383         WInDev[wDevID].unixdev = audio;
1384         WInDev[wDevID].bufsize = abuf_size;
1385         WInDev[wDevID].dwTotalRecorded = 0;
1386         memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
1387         lpFormat = (LPWAVEFORMAT) lpDesc->lpFormat; 
1388         if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
1389                 dprintf_mciwave(stddeb,"Linux 'widOpen' // Bad format %04X !\n",
1390                                         lpFormat->wFormatTag);
1391                 return WAVERR_BADFORMAT;
1392         }
1393         memcpy(&WInDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
1394         WInDev[wDevID].Format.wBitsPerSample = 8; /* <-------------- */
1395         if (WInDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
1396         if (WInDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
1397         if (WInDev[wDevID].Format.wBitsPerSample == 0) {
1398                 WInDev[wDevID].Format.wBitsPerSample = 8 *
1399                 (WInDev[wDevID].Format.wf.nAvgBytesPerSec /
1400                 WInDev[wDevID].Format.wf.nSamplesPerSec) /
1401                 WInDev[wDevID].Format.wf.nChannels;
1402         }
1403         samplesize = WInDev[wDevID].Format.wBitsPerSample;
1404         smplrate = WInDev[wDevID].Format.wf.nSamplesPerSec;
1405         dsp_stereo = (WInDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
1406         IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
1407         IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
1408         IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
1409         dprintf_mciwave(stddeb,"Linux 'widOpen' // wBitsPerSample=%u !\n",
1410                                 WInDev[wDevID].Format.wBitsPerSample);
1411         dprintf_mciwave(stddeb,"Linux 'widOpen' // nSamplesPerSec=%lu !\n",
1412                                 WInDev[wDevID].Format.wf.nSamplesPerSec);
1413         dprintf_mciwave(stddeb,"Linux 'widOpen' // nChannels=%u !\n",
1414                                 WInDev[wDevID].Format.wf.nChannels);
1415         dprintf_mciwave(stddeb,"Linux 'widOpen' // nAvgBytesPerSec=%lu\n",
1416                         WInDev[wDevID].Format.wf.nAvgBytesPerSec); 
1417         if (WAVE_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
1418                 dprintf_mciwave(stddeb,"Linux 'widOpen' // can't notify client !\n");
1419                 return MMSYSERR_INVALPARAM;
1420         }
1421         return MMSYSERR_NOERROR;
1422 }
1423
1424 /**************************************************************************
1425  *                              widClose                        [internal]
1426  */
1427 static DWORD widClose(WORD wDevID)
1428 {
1429         dprintf_mciwave(stddeb,"widClose(%u);\n", wDevID);
1430         if (wDevID > MAX_WAVINDRV) return MMSYSERR_INVALPARAM;
1431         if (WInDev[wDevID].unixdev == 0) {
1432                 dprintf_mciwave(stddeb,"Linux 'widClose' // can't close !\n");
1433                 return MMSYSERR_NOTENABLED;
1434         }
1435         if (WInDev[wDevID].lpQueueHdr != NULL) {
1436                 dprintf_mciwave(stddeb,"linux 'widclose' // still buffers open !\n");
1437                 return WAVERR_STILLPLAYING;
1438         }
1439         close(WInDev[wDevID].unixdev);
1440         WInDev[wDevID].unixdev = 0;
1441         WInDev[wDevID].bufsize = 0;
1442         if (WAVE_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
1443                 dprintf_mciwave(stddeb,"Linux 'widClose' // can't notify client !\n");
1444                 return MMSYSERR_INVALPARAM;
1445         }
1446         return MMSYSERR_NOERROR;
1447 }
1448
1449 /**************************************************************************
1450  *                              widAddBuffer            [internal]
1451  */
1452 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1453 {
1454         int             count   = 1;
1455         LPWAVEHDR       lpWIHdr;
1456
1457         dprintf_mciwave(stddeb,
1458                 "widAddBuffer(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1459         if (WInDev[wDevID].unixdev == 0) {
1460                 dprintf_mciwave(stddeb,"Linux 'widAddBuffer' // can't do it !\n");
1461                 return MMSYSERR_NOTENABLED;
1462         }
1463         if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
1464                 dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // never been prepared !\n");
1465                 return WAVERR_UNPREPARED;
1466         }
1467         if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
1468                 dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // header already in use !\n");
1469                 return WAVERR_STILLPLAYING;
1470         }
1471         lpWaveHdr->dwFlags |= WHDR_PREPARED;
1472         lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1473         lpWaveHdr->dwFlags &= ~WHDR_DONE;
1474         lpWaveHdr->dwBytesRecorded = 0;
1475         if (WInDev[wDevID].lpQueueHdr == NULL) {
1476                 WInDev[wDevID].lpQueueHdr = lpWaveHdr;
1477         } else {
1478                 lpWIHdr = WInDev[wDevID].lpQueueHdr;
1479                 while (lpWIHdr->lpNext != NULL) {
1480                         lpWIHdr = lpWIHdr->lpNext;
1481                         count++;
1482                 }
1483                 lpWIHdr->lpNext = lpWaveHdr;
1484                 lpWaveHdr->lpNext = NULL;
1485                 count++;
1486         }
1487         dprintf_mciwave(stddeb,
1488                 "widAddBuffer // buffer added ! (now %u in queue)\n", count);
1489         return MMSYSERR_NOERROR;
1490 }
1491
1492 /**************************************************************************
1493  *                              widPrepare                      [internal]
1494  */
1495 static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1496 {
1497         dprintf_mciwave(stddeb,
1498                 "widPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1499         if (WInDev[wDevID].unixdev == 0) {
1500                 dprintf_mciwave(stddeb,"Linux 'widPrepare' // can't prepare !\n");
1501                 return MMSYSERR_NOTENABLED;
1502         }
1503         if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1504                 return WAVERR_STILLPLAYING;
1505         lpWaveHdr->dwFlags |= WHDR_PREPARED;
1506         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1507         lpWaveHdr->dwFlags &= ~WHDR_DONE;
1508         lpWaveHdr->dwBytesRecorded = 0;
1509         dprintf_mciwave(stddeb,"Linux 'widPrepare' // header prepared !\n");
1510         return MMSYSERR_NOERROR;
1511 }
1512
1513 /**************************************************************************
1514  *                              widUnprepare                    [internal]
1515  */
1516 static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1517 {
1518         dprintf_mciwave(stddeb,
1519                 "widUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1520         if (WInDev[wDevID].unixdev == 0) {
1521                 dprintf_mciwave(stddeb,"Linux 'widUnprepare' // can't unprepare !\n");
1522                 return MMSYSERR_NOTENABLED;
1523         }
1524         lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1525         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1526         lpWaveHdr->dwFlags |= WHDR_DONE;
1527
1528         dprintf_mciwave(stddeb, "Linux 'widUnprepare' // all headers unprepared !\n");
1529         return MMSYSERR_NOERROR;
1530 }
1531
1532 /**************************************************************************
1533  *                      widStart                                [internal]
1534  */
1535 static DWORD widStart(WORD wDevID)
1536 {
1537         int             count   = 1;
1538         int             bytesRead;
1539         LPWAVEHDR       lpWIHdr;
1540         LPWAVEHDR       *lpWaveHdr;
1541
1542         dprintf_mciwave(stddeb,"widStart(%u);\n", wDevID);
1543         if (WInDev[wDevID].unixdev == 0) {
1544                 dprintf_mciwave(stddeb, "Linux 'widStart' // can't start recording !\n");
1545                 return MMSYSERR_NOTENABLED;
1546         }
1547
1548         lpWaveHdr = &(WInDev[wDevID].lpQueueHdr);
1549         dprintf_mciwave(stddeb,"Linux 'widstart'// lpWaveHdr = %08lx\n",(DWORD)lpWaveHdr);
1550         if (!*lpWaveHdr || !(*lpWaveHdr)->lpData) {
1551                 dprintf_mciwave(stddeb,"Linux 'widStart' // never been prepared !\n");
1552                 return WAVERR_UNPREPARED;
1553         }
1554
1555         while(*lpWaveHdr != NULL) {
1556                 lpWIHdr = *lpWaveHdr;
1557                 dprintf_mciwave(stddeb,
1558                         "widStart // recording buf#%u=%p size=%lu \n",
1559                         count, lpWIHdr->lpData, lpWIHdr->dwBufferLength);
1560                 fflush(stddeb);
1561                 bytesRead = read (WInDev[wDevID].unixdev, 
1562                         lpWIHdr->lpData,
1563                         lpWIHdr->dwBufferLength);
1564                 if (bytesRead==-1)
1565                         perror("read from audio device");
1566                 fprintf(stderr,"bytesread = %d (%ld)\n",bytesRead,lpWIHdr->dwBufferLength);
1567                 lpWIHdr->dwBytesRecorded = bytesRead;
1568                 WInDev[wDevID].dwTotalRecorded += lpWIHdr->dwBytesRecorded;
1569                 lpWIHdr->dwFlags &= ~WHDR_INQUEUE;
1570                 lpWIHdr->dwFlags |= WHDR_DONE;
1571
1572                 /* FIXME: should pass segmented pointer here, do we need that?*/
1573                 if (WAVE_NotifyClient(wDevID, WIM_DATA, (DWORD)lpWaveHdr, lpWIHdr->dwBytesRecorded) != MMSYSERR_NOERROR) {
1574                         dprintf_mciwave(stddeb, "Linux 'widStart' // can't notify client !\n");
1575                         return MMSYSERR_INVALPARAM;
1576                 }
1577                 /* removes the current block from the queue */
1578                 *lpWaveHdr = lpWIHdr->lpNext;
1579                 count++;
1580         }
1581         dprintf_mciwave(stddeb,"widStart // end of recording !\n");
1582         fflush(stddeb);
1583         return MMSYSERR_NOERROR;
1584 }
1585
1586 /**************************************************************************
1587  *                      widStop                                 [internal]
1588  */
1589 static DWORD widStop(WORD wDevID)
1590 {
1591         dprintf_mciwave(stddeb,"widStop(%u);\n", wDevID);
1592         if (WInDev[wDevID].unixdev == 0) {
1593                 dprintf_mciwave(stddeb,"Linux 'widStop' // can't stop !\n");
1594                 return MMSYSERR_NOTENABLED;
1595         }
1596         return MMSYSERR_NOERROR;
1597 }
1598
1599 /**************************************************************************
1600  *                      widReset                                [internal]
1601  */
1602 static DWORD widReset(WORD wDevID)
1603 {
1604         dprintf_mciwave(stddeb,"widReset(%u);\n", wDevID);
1605         if (WInDev[wDevID].unixdev == 0) {
1606                 dprintf_mciwave(stddeb,"Linux 'widReset' // can't reset !\n");
1607                 return MMSYSERR_NOTENABLED;
1608         }
1609         return MMSYSERR_NOERROR;
1610 }
1611
1612 /**************************************************************************
1613  *                              widGetPosition                  [internal]
1614  */
1615 static DWORD widGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
1616 {
1617         int             time;
1618     
1619         dprintf_mciwave(stddeb,
1620                 "widGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1621         if (WInDev[wDevID].unixdev == 0) {
1622                 dprintf_mciwave(stddeb,"Linux 'widGetPosition' // can't get pos !\n");
1623                 return MMSYSERR_NOTENABLED;
1624         }
1625         if (lpTime == NULL)     return MMSYSERR_INVALPARAM;
1626         dprintf_mciwave(stddeb,"widGetPosition // wType=%04X !\n", 
1627                         lpTime->wType);
1628         dprintf_mciwave(stddeb,"widGetPosition // wBitsPerSample=%u\n",
1629                         WInDev[wDevID].Format.wBitsPerSample); 
1630         dprintf_mciwave(stddeb,"widGetPosition // nSamplesPerSec=%lu\n",
1631                         WInDev[wDevID].Format.wf.nSamplesPerSec); 
1632         dprintf_mciwave(stddeb,"widGetPosition // nChannels=%u\n",
1633                         WInDev[wDevID].Format.wf.nChannels); 
1634         dprintf_mciwave(stddeb,"widGetPosition // nAvgBytesPerSec=%lu\n",
1635                         WInDev[wDevID].Format.wf.nAvgBytesPerSec); 
1636         fflush(stddeb);
1637         switch(lpTime->wType) {
1638         case TIME_BYTES:
1639                 lpTime->u.cb = WInDev[wDevID].dwTotalRecorded;
1640                 dprintf_mciwave(stddeb,
1641                     "widGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb);
1642                 break;
1643         case TIME_SAMPLES:
1644                 lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 /
1645                                   WInDev[wDevID].Format.wBitsPerSample;
1646                 dprintf_mciwave(stddeb,
1647                                 "widGetPosition // TIME_SAMPLES=%lu\n", 
1648                                 lpTime->u.sample);
1649                 break;
1650         case TIME_SMPTE:
1651                 time = WInDev[wDevID].dwTotalRecorded /
1652                         (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1653                 lpTime->u.smpte.hour = time / 108000;
1654                 time -= lpTime->u.smpte.hour * 108000;
1655                 lpTime->u.smpte.min = time / 1800;
1656                 time -= lpTime->u.smpte.min * 1800;
1657                 lpTime->u.smpte.sec = time / 30;
1658                 time -= lpTime->u.smpte.sec * 30;
1659                 lpTime->u.smpte.frame = time;
1660                 lpTime->u.smpte.fps = 30;
1661 dprintf_mciwave(stddeb,"widGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1662                                 lpTime->u.smpte.hour, lpTime->u.smpte.min,
1663                                 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1664                 break;
1665         default:
1666                 dprintf_mciwave(stddeb,"widGetPosition() format not supported ! use TIME_MS !\n");
1667                 lpTime->wType = TIME_MS;
1668         case TIME_MS:
1669                 lpTime->u.ms = WInDev[wDevID].dwTotalRecorded /
1670                                 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1671                 dprintf_mciwave(stddeb,
1672                       "widGetPosition // TIME_MS=%lu\n", lpTime->u.ms);
1673                 break;
1674         }
1675         return MMSYSERR_NOERROR;
1676 }
1677
1678 /**************************************************************************
1679  *                              widMessage                      [sample driver]
1680  */
1681 DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1682                                         DWORD dwParam1, DWORD dwParam2)
1683 {
1684         dprintf_mciwave(stddeb,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1685                         wDevID, wMsg, dwUser, dwParam1, dwParam2);
1686         switch(wMsg) {
1687         case WIDM_OPEN:
1688                 return widOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1689         case WIDM_CLOSE:
1690                 return widClose(wDevID);
1691         case WIDM_ADDBUFFER:
1692                 return widAddBuffer(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1693         case WIDM_PREPARE:
1694                 return widPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1695         case WIDM_UNPREPARE:
1696                 return widUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1697         case WIDM_GETDEVCAPS:
1698                 return widGetDevCaps(wDevID, (LPWAVEINCAPS16)dwParam1,dwParam2);
1699         case WIDM_GETNUMDEVS:
1700                 return 1;
1701         case WIDM_GETPOS:
1702                 return widGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1703         case WIDM_RESET:
1704                 return widReset(wDevID);
1705         case WIDM_START:
1706                 return widStart(wDevID);
1707         case WIDM_PAUSE:
1708                 return widStop(wDevID);
1709         case WIDM_STOP:
1710                 return widStop(wDevID);
1711         default:
1712                 dprintf_mciwave(stddeb,"widMessage // unknown message !\n");
1713         }
1714         return MMSYSERR_NOTSUPPORTED;
1715 }
1716
1717
1718 /**************************************************************************
1719  *                              AUDIO_DriverProc                [sample driver]
1720  */
1721 LONG WAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, 
1722                      DWORD dwParam1, DWORD dwParam2)
1723 {
1724         dprintf_mciwave(stddeb,"WAVE_DriverProc(%08lX, %04X, %04X, %08lX, %08lX)\n", 
1725                 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1726         switch(wMsg) {
1727         case DRV_LOAD:
1728                 return 1;
1729         case DRV_FREE:
1730                 return 1;
1731         case DRV_OPEN:
1732                 return 1;
1733         case DRV_CLOSE:
1734                 return 1;
1735         case DRV_ENABLE:
1736                 return 1;
1737         case DRV_DISABLE:
1738                 return 1;
1739         case DRV_QUERYCONFIGURE:
1740                 return 1;
1741         case DRV_CONFIGURE:
1742                 MessageBox16(0, "Sample MultiMedia Linux Driver !", 
1743                                                         "MMLinux Driver", MB_OK);
1744                 return 1;
1745         case DRV_INSTALL:
1746                 return DRVCNF_RESTART;
1747         case DRV_REMOVE:
1748                 return DRVCNF_RESTART;
1749         case MCI_OPEN_DRIVER:
1750         case MCI_OPEN:
1751                 return WAVE_mciOpen(dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS16)PTR_SEG_TO_LIN(dwParam2));
1752         case MCI_CUE:
1753                 return WAVE_mciCue(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1754         case MCI_CLOSE_DRIVER:
1755         case MCI_CLOSE:
1756                 return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1757         case MCI_PLAY:
1758                 return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
1759         case MCI_RECORD:
1760                 return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2));
1761         case MCI_STOP:
1762                 return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1763         case MCI_SET:
1764                 return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
1765         case MCI_PAUSE:
1766                 return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1767         case MCI_RESUME:
1768                 return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1769         case MCI_STATUS:
1770                 return WAVE_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1771         case MCI_GETDEVCAPS:
1772                 return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1773         case MCI_INFO:
1774                 return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(dwParam2));
1775
1776         case MCI_LOAD:
1777                 return MMSYSERR_NOTSUPPORTED;
1778         case MCI_SAVE:
1779                 return MMSYSERR_NOTSUPPORTED;
1780         case MCI_SEEK:
1781                 return MMSYSERR_NOTSUPPORTED;
1782         case MCI_FREEZE:
1783                 return MMSYSERR_NOTSUPPORTED;
1784         case MCI_PUT:
1785                 return MMSYSERR_NOTSUPPORTED;
1786         case MCI_REALIZE:
1787                 return MMSYSERR_NOTSUPPORTED;
1788         case MCI_UNFREEZE:
1789                 return MMSYSERR_NOTSUPPORTED;
1790         case MCI_UPDATE:
1791                 return MMSYSERR_NOTSUPPORTED;
1792         case MCI_WHERE:
1793                 return MMSYSERR_NOTSUPPORTED;
1794         case MCI_WINDOW:
1795                 return MMSYSERR_NOTSUPPORTED;
1796         case MCI_STEP:
1797                 return MMSYSERR_NOTSUPPORTED;
1798         case MCI_SPIN:
1799                 return MMSYSERR_NOTSUPPORTED;
1800         case MCI_ESCAPE:
1801                 return MMSYSERR_NOTSUPPORTED;
1802         case MCI_COPY:
1803                 return MMSYSERR_NOTSUPPORTED;
1804         case MCI_CUT:
1805                 return MMSYSERR_NOTSUPPORTED;
1806         case MCI_DELETE:
1807                 return MMSYSERR_NOTSUPPORTED;
1808         case MCI_PASTE:
1809                 return MMSYSERR_NOTSUPPORTED;
1810
1811         default:
1812                 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1813         }
1814         return MMSYSERR_NOTENABLED;
1815 }
1816
1817 #else /* !HAVE_OSS */
1818
1819 /**************************************************************************
1820  *                              wodMessage                      [sample driver]
1821  */
1822 DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1823                                         DWORD dwParam1, DWORD dwParam2)
1824 {
1825         fprintf(stderr,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1826                         wDevID, wMsg, dwUser, dwParam1, dwParam2);
1827         return MMSYSERR_NOTENABLED;
1828 }
1829
1830 /**************************************************************************
1831  *                              widMessage                      [sample driver]
1832  */
1833 DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1834                                         DWORD dwParam1, DWORD dwParam2)
1835 {
1836         fprintf(stderr,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1837                         wDevID, wMsg, dwUser, dwParam1, dwParam2);
1838         return MMSYSERR_NOTENABLED;
1839 }
1840
1841 /**************************************************************************
1842  *                              AUDIO_DriverProc                [sample driver]
1843  */
1844 LONG WAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, 
1845                      DWORD dwParam1, DWORD dwParam2)
1846 {
1847         return MMSYSERR_NOTENABLED;
1848 }
1849 #endif /* HAVE_OSS */