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