1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
5 * Copyright 1994 Martin Ayotte
9 * - record/play should and must be done asynchronous
10 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
21 #include <sys/ioctl.h>
22 #include "wine/winuser16.h"
25 #include "multimedia.h"
32 #define SOUND_DEV "/dev/dsp"
33 #define MIXER_DEV "/dev/mixer"
36 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
38 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
41 #define MAX_WAVEOUTDRV (1)
42 #define MAX_WAVEINDRV (1)
48 WAVEOPENDESC waveDesc
;
58 DWORD bufsize
; /* OpenSound '/dev/dsp' give us that size */
59 WAVEOPENDESC waveDesc
;
63 DWORD dwTotalRecorded
;
66 static WINE_WAVEOUT WOutDev
[MAX_WAVEOUTDRV
];
67 static WINE_WAVEIN WInDev
[MAX_WAVEOUTDRV
];
69 /*======================================================================*
70 * Low level WAVE implemantation *
71 *======================================================================*/
73 /**************************************************************************
74 * WAVE_NotifyClient [internal]
76 static DWORD
WAVE_NotifyClient(UINT16 wDevID
, WORD wMsg
,
77 DWORD dwParam1
, DWORD dwParam2
)
79 TRACE(wave
,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID
, wMsg
, dwParam1
, dwParam2
);
85 if (wDevID
> MAX_WAVEOUTDRV
) return MCIERR_INTERNAL
;
87 if (WOutDev
[wDevID
].wFlags
!= DCB_NULL
&&
89 WOutDev
[wDevID
].waveDesc
.dwCallBack
,
90 WOutDev
[wDevID
].wFlags
,
91 WOutDev
[wDevID
].waveDesc
.hWave
,
93 WOutDev
[wDevID
].waveDesc
.dwInstance
,
96 WARN(wave
, "can't notify client !\n");
97 return MMSYSERR_NOERROR
;
104 if (wDevID
> MAX_WAVEINDRV
) return MCIERR_INTERNAL
;
106 if (WInDev
[wDevID
].wFlags
!= DCB_NULL
&&
108 WInDev
[wDevID
].waveDesc
.dwCallBack
,
109 WInDev
[wDevID
].wFlags
,
110 WInDev
[wDevID
].waveDesc
.hWave
,
112 WInDev
[wDevID
].waveDesc
.dwInstance
,
115 WARN(wave
, "can't notify client !\n");
116 return MMSYSERR_NOERROR
;
123 /**************************************************************************
124 * wodGetDevCaps [internal]
126 static DWORD
wodGetDevCaps(WORD wDevID
, LPWAVEOUTCAPS16 lpCaps
, DWORD dwSize
)
134 TRACE(wave
, "(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
135 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
136 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
137 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
138 if (audio
== -1) return MMSYSERR_ALLOCATED
;
140 lpCaps
->wMid
= 0x0002;
141 lpCaps
->wPid
= 0x0104;
142 strcpy(lpCaps
->szPname
, "SB16 Wave Out");
144 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
145 lpCaps
->wPid
= 0x0001; /* Product ID */
146 strcpy(lpCaps
->szPname
, "OpenSoundSystem WAVOUT Driver");
148 lpCaps
->vDriverVersion
= 0x0100;
149 lpCaps
->dwFormats
= 0x00000000;
150 lpCaps
->dwSupport
= WAVECAPS_VOLUME
;
152 /* First bytespersampl, then stereo */
153 bytespersmpl
= (IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
) != 0) ? 1 : 2;
155 lpCaps
->wChannels
= (IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
) != 0) ? 1 : 2;
156 if (lpCaps
->wChannels
> 1) lpCaps
->dwSupport
|= WAVECAPS_LRVOLUME
;
159 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
160 lpCaps
->dwFormats
|= WAVE_FORMAT_4M08
;
161 if (lpCaps
->wChannels
> 1)
162 lpCaps
->dwFormats
|= WAVE_FORMAT_4S08
;
163 if (bytespersmpl
> 1) {
164 lpCaps
->dwFormats
|= WAVE_FORMAT_4M16
;
165 if (lpCaps
->wChannels
> 1)
166 lpCaps
->dwFormats
|= WAVE_FORMAT_4S16
;
170 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
171 lpCaps
->dwFormats
|= WAVE_FORMAT_2M08
;
172 if (lpCaps
->wChannels
> 1)
173 lpCaps
->dwFormats
|= WAVE_FORMAT_2S08
;
174 if (bytespersmpl
> 1) {
175 lpCaps
->dwFormats
|= WAVE_FORMAT_2M16
;
176 if (lpCaps
->wChannels
> 1)
177 lpCaps
->dwFormats
|= WAVE_FORMAT_2S16
;
181 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
182 lpCaps
->dwFormats
|= WAVE_FORMAT_1M08
;
183 if (lpCaps
->wChannels
> 1)
184 lpCaps
->dwFormats
|= WAVE_FORMAT_1S08
;
185 if (bytespersmpl
> 1) {
186 lpCaps
->dwFormats
|= WAVE_FORMAT_1M16
;
187 if (lpCaps
->wChannels
> 1)
188 lpCaps
->dwFormats
|= WAVE_FORMAT_1S16
;
192 TRACE(wave
, "dwFormats = %08lX\n", lpCaps
->dwFormats
);
193 return MMSYSERR_NOERROR
;
197 /**************************************************************************
200 static DWORD
wodOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
202 int audio
,abuf_size
,smplrate
,samplesize
,dsp_stereo
;
203 LPWAVEFORMAT lpFormat
;
205 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
206 if (lpDesc
== NULL
) {
207 WARN(wave
, "Invalid Parameter !\n");
208 return MMSYSERR_INVALPARAM
;
210 if (wDevID
>= MAX_WAVEOUTDRV
) {
211 TRACE(wave
,"MAX_WAVOUTDRV reached !\n");
212 return MMSYSERR_ALLOCATED
;
214 WOutDev
[wDevID
].unixdev
= 0;
215 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
216 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
218 WARN(wave
, "can't open !\n");
219 return MMSYSERR_ALLOCATED
;
221 IOCTL(audio
, SNDCTL_DSP_GETBLKSIZE
, abuf_size
);
222 if (abuf_size
< 1024 || abuf_size
> 65536) {
224 WARN(wave
, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
226 WARN(wave
, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
227 return MMSYSERR_NOTENABLED
;
229 WOutDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
230 switch(WOutDev
[wDevID
].wFlags
) {
232 TRACE(wave
, "CALLBACK_NULL !\n");
235 TRACE(wave
, "CALLBACK_WINDOW !\n");
238 TRACE(wave
, "CALLBACK_TASK !\n");
241 TRACE(wave
, "CALLBACK_FUNCTION !\n");
244 WOutDev
[wDevID
].lpQueueHdr
= NULL
;
245 WOutDev
[wDevID
].unixdev
= audio
;
246 WOutDev
[wDevID
].dwTotalPlayed
= 0;
247 WOutDev
[wDevID
].bufsize
= abuf_size
;
248 /* FIXME: copy lpFormat too? */
249 memcpy(&WOutDev
[wDevID
].waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
250 TRACE(wave
,"lpDesc->lpFormat = %p\n",lpDesc
->lpFormat
);
251 lpFormat
= lpDesc
->lpFormat
;
252 TRACE(wave
,"lpFormat = %p\n",lpFormat
);
253 if (lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
254 WARN(wave
,"Bad format %04X !\n", lpFormat
->wFormatTag
);
255 WARN(wave
,"Bad nChannels %d !\n", lpFormat
->nChannels
);
256 WARN(wave
,"Bad nSamplesPerSec %ld !\n", lpFormat
->nSamplesPerSec
);
257 return WAVERR_BADFORMAT
;
259 memcpy(&WOutDev
[wDevID
].Format
, lpFormat
, sizeof(PCMWAVEFORMAT
));
260 if (WOutDev
[wDevID
].Format
.wf
.nChannels
== 0) return WAVERR_BADFORMAT
;
261 if (WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
== 0) return WAVERR_BADFORMAT
;
262 TRACE(wave
,"wBitsPerSample=%u !\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
263 if (WOutDev
[wDevID
].Format
.wBitsPerSample
== 0) {
264 WOutDev
[wDevID
].Format
.wBitsPerSample
= 8 *
265 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/
266 WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
) /
267 WOutDev
[wDevID
].Format
.wf
.nChannels
;
269 samplesize
= WOutDev
[wDevID
].Format
.wBitsPerSample
;
270 smplrate
= WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
;
271 dsp_stereo
= (WOutDev
[wDevID
].Format
.wf
.nChannels
> 1) ? TRUE
: FALSE
;
273 /* First size and stereo then samplerate */
274 IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
);
275 IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
);
276 IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
);
278 TRACE(wave
,"wBitsPerSample=%u !\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
279 TRACE(wave
,"nAvgBytesPerSec=%lu !\n", WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
280 TRACE(wave
,"nSamplesPerSec=%lu !\n", WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
281 TRACE(wave
,"nChannels=%u !\n", WOutDev
[wDevID
].Format
.wf
.nChannels
);
282 if (WAVE_NotifyClient(wDevID
, WOM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
283 WARN(wave
, "can't notify client !\n");
284 return MMSYSERR_INVALPARAM
;
286 return MMSYSERR_NOERROR
;
289 /**************************************************************************
290 * wodClose [internal]
292 static DWORD
wodClose(WORD wDevID
)
294 TRACE(wave
,"(%u);\n", wDevID
);
296 if (wDevID
> MAX_WAVEOUTDRV
) return MMSYSERR_INVALPARAM
;
297 if (WOutDev
[wDevID
].unixdev
== 0) {
298 WARN(wave
, "can't close !\n");
299 return MMSYSERR_NOTENABLED
;
301 if (WOutDev
[wDevID
].lpQueueHdr
!= NULL
) {
302 WARN(wave
, "still buffers open !\n");
303 /* Don't care. Who needs those buffers anyway */
304 /*return WAVERR_STILLPLAYING; */
306 close(WOutDev
[wDevID
].unixdev
);
307 WOutDev
[wDevID
].unixdev
= 0;
308 WOutDev
[wDevID
].bufsize
= 0;
309 WOutDev
[wDevID
].lpQueueHdr
= NULL
;
310 if (WAVE_NotifyClient(wDevID
, WOM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
311 WARN(wave
, "can't notify client !\n");
312 return MMSYSERR_INVALPARAM
;
314 return MMSYSERR_NOERROR
;
317 /**************************************************************************
318 * wodWrite [internal]
319 * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
320 * device, and initiate async playing.
322 static DWORD
wodWrite(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
328 TRACE(wave
,"(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
329 if (WOutDev
[wDevID
].unixdev
== 0) {
330 WARN(wave
, "can't play !\n");
331 return MMSYSERR_NOTENABLED
;
333 if (lpWaveHdr
->lpData
== NULL
) return WAVERR_UNPREPARED
;
334 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) return WAVERR_UNPREPARED
;
335 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) return WAVERR_STILLPLAYING
;
336 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
337 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
338 TRACE(wave
, "dwBufferLength %lu !\n", lpWaveHdr
->dwBufferLength
);
339 TRACE(wave
, "WOutDev[%u].unixdev %u !\n", wDevID
, WOutDev
[wDevID
].unixdev
);
340 lpData
= lpWaveHdr
->lpData
;
341 count
= write (WOutDev
[wDevID
].unixdev
, lpData
, lpWaveHdr
->dwBufferLength
);
342 TRACE(wave
,"write returned count %u !\n",count
);
343 if (count
!= lpWaveHdr
->dwBufferLength
) {
344 WARN(wave
, " error writing !\n");
345 return MMSYSERR_NOTENABLED
;
347 WOutDev
[wDevID
].dwTotalPlayed
+= count
;
348 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
349 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
350 if ((DWORD
)lpWaveHdr
->lpData
!=lpWaveHdr
->reserved
) {
351 /* FIXME: what if it expects it's OWN lpwavehdr back? */
352 xwavehdr
= SEGPTR_NEW(WAVEHDR
);
353 memcpy(xwavehdr
,lpWaveHdr
,sizeof(WAVEHDR
));
354 xwavehdr
->lpData
= (LPBYTE
)xwavehdr
->reserved
;
355 if (WAVE_NotifyClient(wDevID
, WOM_DONE
, (DWORD
)SEGPTR_GET(xwavehdr
), count
) != MMSYSERR_NOERROR
) {
356 WARN(wave
, "can't notify client !\n");
357 SEGPTR_FREE(xwavehdr
);
358 return MMSYSERR_INVALPARAM
;
360 SEGPTR_FREE(xwavehdr
);
362 if (WAVE_NotifyClient(wDevID
, WOM_DONE
, (DWORD
)lpWaveHdr
, count
) != MMSYSERR_NOERROR
) {
363 WARN(wave
, "can't notify client !\n");
364 return MMSYSERR_INVALPARAM
;
367 return MMSYSERR_NOERROR
;
370 /**************************************************************************
371 * wodPrepare [internal]
373 static DWORD
wodPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
375 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
376 if (WOutDev
[wDevID
].unixdev
== 0) {
377 WARN(wave
, "can't prepare !\n");
378 return MMSYSERR_NOTENABLED
;
380 /* don't append to queue, wodWrite does that */
381 WOutDev
[wDevID
].dwTotalPlayed
= 0;
382 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
383 return WAVERR_STILLPLAYING
;
384 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
385 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
386 return MMSYSERR_NOERROR
;
389 /**************************************************************************
390 * wodUnprepare [internal]
392 static DWORD
wodUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
394 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
395 if (WOutDev
[wDevID
].unixdev
== 0) {
396 WARN(wave
, "can't unprepare !\n");
397 return MMSYSERR_NOTENABLED
;
399 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
400 return WAVERR_STILLPLAYING
;
402 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
403 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
404 TRACE(wave
, "all headers unprepared !\n");
405 return MMSYSERR_NOERROR
;
408 /**************************************************************************
409 * wodRestart [internal]
411 static DWORD
wodRestart(WORD wDevID
)
413 TRACE(wave
,"(%u);\n", wDevID
);
414 if (WOutDev
[wDevID
].unixdev
== 0) {
415 WARN(wave
, "can't restart !\n");
416 return MMSYSERR_NOTENABLED
;
418 /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
419 /* FIXME: Myst crashes with this ... hmm -MM
420 if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
421 WARN(wave, "can't notify client !\n");
422 return MMSYSERR_INVALPARAM;
426 return MMSYSERR_NOERROR
;
429 /**************************************************************************
430 * wodReset [internal]
432 static DWORD
wodReset(WORD wDevID
)
434 TRACE(wave
,"(%u);\n", wDevID
);
435 if (WOutDev
[wDevID
].unixdev
== 0) {
436 WARN(wave
, "can't reset !\n");
437 return MMSYSERR_NOTENABLED
;
439 return MMSYSERR_NOERROR
;
443 /**************************************************************************
444 * wodGetPosition [internal]
446 static DWORD
wodGetPosition(WORD wDevID
, LPMMTIME16 lpTime
, DWORD uSize
)
449 TRACE(wave
,"(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
450 if (WOutDev
[wDevID
].unixdev
== 0) {
451 WARN(wave
, "can't get pos !\n");
452 return MMSYSERR_NOTENABLED
;
454 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
455 TRACE(wave
,"wType=%04X !\n", lpTime
->wType
);
456 TRACE(wave
,"wBitsPerSample=%u\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
457 TRACE(wave
,"nSamplesPerSec=%lu\n", WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
458 TRACE(wave
,"nChannels=%u\n", WOutDev
[wDevID
].Format
.wf
.nChannels
);
459 TRACE(wave
,"nAvgBytesPerSec=%lu\n", WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
460 switch(lpTime
->wType
) {
462 lpTime
->u
.cb
= WOutDev
[wDevID
].dwTotalPlayed
;
463 TRACE(wave
,"TIME_BYTES=%lu\n", lpTime
->u
.cb
);
466 TRACE(wave
,"dwTotalPlayed=%lu\n", WOutDev
[wDevID
].dwTotalPlayed
);
467 TRACE(wave
,"wBitsPerSample=%u\n", WOutDev
[wDevID
].Format
.wBitsPerSample
);
468 lpTime
->u
.sample
= WOutDev
[wDevID
].dwTotalPlayed
* 8 /
469 WOutDev
[wDevID
].Format
.wBitsPerSample
;
470 TRACE(wave
,"TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
473 time
= WOutDev
[wDevID
].dwTotalPlayed
/
474 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
475 lpTime
->u
.smpte
.hour
= time
/ 108000;
476 time
-= lpTime
->u
.smpte
.hour
* 108000;
477 lpTime
->u
.smpte
.min
= time
/ 1800;
478 time
-= lpTime
->u
.smpte
.min
* 1800;
479 lpTime
->u
.smpte
.sec
= time
/ 30;
480 time
-= lpTime
->u
.smpte
.sec
* 30;
481 lpTime
->u
.smpte
.frame
= time
;
482 lpTime
->u
.smpte
.fps
= 30;
483 TRACE(wave
, "wodGetPosition , TIME_SMPTE=%02u:%02u:%02u:%02u\n",
484 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
485 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
488 FIXME(wave
, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime
->wType
);
489 lpTime
->wType
= TIME_MS
;
491 lpTime
->u
.ms
= WOutDev
[wDevID
].dwTotalPlayed
/
492 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
493 TRACE(wave
,"wodGetPosition , TIME_MS=%lu\n", lpTime
->u
.ms
);
496 return MMSYSERR_NOERROR
;
499 /**************************************************************************
500 * wodGetVolume [internal]
502 static DWORD
wodGetVolume(WORD wDevID
, LPDWORD lpdwVol
)
505 int volume
, left
, right
;
506 TRACE(wave
,"(%u, %p);\n", wDevID
, lpdwVol
);
507 if (lpdwVol
== NULL
) return MMSYSERR_NOTENABLED
;
508 if ((mixer
= open(MIXER_DEV
, O_RDONLY
)) < 0) {
509 WARN(wave
, "mixer device not available !\n");
510 return MMSYSERR_NOTENABLED
;
512 if (ioctl(mixer
, SOUND_MIXER_READ_PCM
, &volume
) == -1) {
513 WARN(wave
, "unable read mixer !\n");
514 return MMSYSERR_NOTENABLED
;
517 left
= volume
& 0x7F;
518 right
= (volume
>> 8) & 0x7F;
519 TRACE(wave
,"left=%d right=%d !\n", left
, right
);
520 *lpdwVol
= MAKELONG(left
<< 9, right
<< 9);
521 return MMSYSERR_NOERROR
;
525 /**************************************************************************
526 * wodSetVolume [internal]
528 static DWORD
wodSetVolume(WORD wDevID
, DWORD dwParam
)
532 TRACE(wave
,"(%u, %08lX);\n", wDevID
, dwParam
);
533 volume
= (LOWORD(dwParam
) >> 9 & 0x7F) +
534 ((HIWORD(dwParam
) >> 9 & 0x7F) << 8);
535 if ((mixer
= open(MIXER_DEV
, O_WRONLY
)) < 0) {
536 WARN(wave
, "mixer device not available !\n");
537 return MMSYSERR_NOTENABLED
;
539 if (ioctl(mixer
, SOUND_MIXER_WRITE_PCM
, &volume
) == -1) {
540 WARN(wave
, "unable set mixer !\n");
541 return MMSYSERR_NOTENABLED
;
544 return MMSYSERR_NOERROR
;
547 /**************************************************************************
548 * wodMessage [sample driver]
550 DWORD WINAPI
wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
551 DWORD dwParam1
, DWORD dwParam2
)
554 TRACE(wave
,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
555 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
558 return wodOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
560 return wodClose(wDevID
);
562 return wodWrite(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
564 return MMSYSERR_NOTSUPPORTED
;
566 return MMSYSERR_NOTSUPPORTED
;
568 return wodGetPosition(wDevID
, (LPMMTIME16
)dwParam1
, dwParam2
);
570 return MMSYSERR_NOTSUPPORTED
;
572 return wodPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
574 return wodUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
575 case WODM_GETDEVCAPS
:
576 return wodGetDevCaps(wDevID
,(LPWAVEOUTCAPS16
)dwParam1
,dwParam2
);
577 case WODM_GETNUMDEVS
:
578 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
579 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
590 return MMSYSERR_NOTSUPPORTED
;
592 return MMSYSERR_NOTSUPPORTED
;
593 case WODM_GETPLAYBACKRATE
:
594 return MMSYSERR_NOTSUPPORTED
;
595 case WODM_SETPLAYBACKRATE
:
596 return MMSYSERR_NOTSUPPORTED
;
598 return wodGetVolume(wDevID
, (LPDWORD
)dwParam1
);
600 return wodSetVolume(wDevID
, dwParam1
);
602 return wodRestart(wDevID
);
604 return wodReset(wDevID
);
606 WARN(wave
,"unknown message !\n");
608 return MMSYSERR_NOTSUPPORTED
;
612 /*-----------------------------------------------------------------------*/
614 /**************************************************************************
615 * widGetDevCaps [internal]
617 static DWORD
widGetDevCaps(WORD wDevID
, LPWAVEINCAPS16 lpCaps
, DWORD dwSize
)
619 int audio
,smplrate
,samplesize
=16,dsp_stereo
=1,bytespersmpl
;
621 TRACE(wave
, "(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
622 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
623 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
624 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
625 if (audio
== -1) return MMSYSERR_ALLOCATED
;
627 lpCaps
->wMid
= 0x0002;
628 lpCaps
->wPid
= 0x0004;
629 strcpy(lpCaps
->szPname
, "SB16 Wave In");
631 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
632 lpCaps
->wPid
= 0x0001; /* Product ID */
633 strcpy(lpCaps
->szPname
, "OpenSoundSystem WAVIN Driver");
635 lpCaps
->dwFormats
= 0x00000000;
636 lpCaps
->wChannels
= (IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
) != 0) ? 1 : 2;
637 bytespersmpl
= (IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
) != 0) ? 1 : 2;
639 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
640 lpCaps
->dwFormats
|= WAVE_FORMAT_4M08
;
641 if (lpCaps
->wChannels
> 1)
642 lpCaps
->dwFormats
|= WAVE_FORMAT_4S08
;
643 if (bytespersmpl
> 1) {
644 lpCaps
->dwFormats
|= WAVE_FORMAT_4M16
;
645 if (lpCaps
->wChannels
> 1)
646 lpCaps
->dwFormats
|= WAVE_FORMAT_4S16
;
650 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
651 lpCaps
->dwFormats
|= WAVE_FORMAT_2M08
;
652 if (lpCaps
->wChannels
> 1)
653 lpCaps
->dwFormats
|= WAVE_FORMAT_2S08
;
654 if (bytespersmpl
> 1) {
655 lpCaps
->dwFormats
|= WAVE_FORMAT_2M16
;
656 if (lpCaps
->wChannels
> 1)
657 lpCaps
->dwFormats
|= WAVE_FORMAT_2S16
;
661 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
662 lpCaps
->dwFormats
|= WAVE_FORMAT_1M08
;
663 if (lpCaps
->wChannels
> 1)
664 lpCaps
->dwFormats
|= WAVE_FORMAT_1S08
;
665 if (bytespersmpl
> 1) {
666 lpCaps
->dwFormats
|= WAVE_FORMAT_1M16
;
667 if (lpCaps
->wChannels
> 1)
668 lpCaps
->dwFormats
|= WAVE_FORMAT_1S16
;
672 TRACE(wave
, "dwFormats = %08lX\n", lpCaps
->dwFormats
);
673 return MMSYSERR_NOERROR
;
677 /**************************************************************************
680 static DWORD
widOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
682 int audio
,abuf_size
,smplrate
,samplesize
,dsp_stereo
;
683 LPWAVEFORMAT lpFormat
;
685 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
686 if (lpDesc
== NULL
) {
687 WARN(wave
, "Invalid Parameter !\n");
688 return MMSYSERR_INVALPARAM
;
690 if (wDevID
>= MAX_WAVEINDRV
) {
691 TRACE(wave
,"MAX_WAVINDRV reached !\n");
692 return MMSYSERR_ALLOCATED
;
694 WInDev
[wDevID
].unixdev
= 0;
695 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
696 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
698 WARN(wave
,"can't open !\n");
699 return MMSYSERR_ALLOCATED
;
701 IOCTL(audio
, SNDCTL_DSP_GETBLKSIZE
, abuf_size
);
702 if (abuf_size
< 1024 || abuf_size
> 65536) {
704 WARN(wave
, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
706 WARN(wave
, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
707 return MMSYSERR_NOTENABLED
;
709 WInDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
710 switch(WInDev
[wDevID
].wFlags
) {
712 TRACE(wave
,"CALLBACK_NULL!\n");
715 TRACE(wave
,"CALLBACK_WINDOW!\n");
718 TRACE(wave
,"CALLBACK_TASK!\n");
721 TRACE(wave
,"CALLBACK_FUNCTION!\n");
724 if (WInDev
[wDevID
].lpQueueHdr
) {
725 HeapFree(GetProcessHeap(),0,WInDev
[wDevID
].lpQueueHdr
);
726 WInDev
[wDevID
].lpQueueHdr
= NULL
;
728 WInDev
[wDevID
].unixdev
= audio
;
729 WInDev
[wDevID
].bufsize
= abuf_size
;
730 WInDev
[wDevID
].dwTotalRecorded
= 0;
731 memcpy(&WInDev
[wDevID
].waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
732 lpFormat
= (LPWAVEFORMAT
) lpDesc
->lpFormat
;
733 if (lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
734 WARN(wave
, "Bad format %04X !\n",
735 lpFormat
->wFormatTag
);
736 return WAVERR_BADFORMAT
;
738 memcpy(&WInDev
[wDevID
].Format
, lpFormat
, sizeof(PCMWAVEFORMAT
));
739 WInDev
[wDevID
].Format
.wBitsPerSample
= 8; /* <-------------- */
740 if (WInDev
[wDevID
].Format
.wf
.nChannels
== 0) return WAVERR_BADFORMAT
;
741 if (WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
== 0) return WAVERR_BADFORMAT
;
742 if (WInDev
[wDevID
].Format
.wBitsPerSample
== 0) {
743 WInDev
[wDevID
].Format
.wBitsPerSample
= 8 *
744 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/
745 WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
) /
746 WInDev
[wDevID
].Format
.wf
.nChannels
;
748 samplesize
= WInDev
[wDevID
].Format
.wBitsPerSample
;
749 smplrate
= WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
;
750 dsp_stereo
= (WInDev
[wDevID
].Format
.wf
.nChannels
> 1) ? TRUE
: FALSE
;
751 IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
);
752 IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
);
753 IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
);
754 TRACE(wave
,"wBitsPerSample=%u !\n", WInDev
[wDevID
].Format
.wBitsPerSample
);
755 TRACE(wave
,"nSamplesPerSec=%lu !\n", WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
756 TRACE(wave
,"nChannels=%u !\n", WInDev
[wDevID
].Format
.wf
.nChannels
);
757 TRACE(wave
,"nAvgBytesPerSec=%lu\n", WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
758 if (WAVE_NotifyClient(wDevID
, WIM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
759 WARN(wave
,"can't notify client !\n");
760 return MMSYSERR_INVALPARAM
;
762 return MMSYSERR_NOERROR
;
765 /**************************************************************************
766 * widClose [internal]
768 static DWORD
widClose(WORD wDevID
)
770 TRACE(wave
,"(%u);\n", wDevID
);
771 if (wDevID
> MAX_WAVEINDRV
) return MMSYSERR_INVALPARAM
;
772 if (WInDev
[wDevID
].unixdev
== 0) {
773 WARN(wave
,"can't close !\n");
774 return MMSYSERR_NOTENABLED
;
776 if (WInDev
[wDevID
].lpQueueHdr
!= NULL
) {
777 WARN(wave
, "still buffers open !\n");
778 return WAVERR_STILLPLAYING
;
780 close(WInDev
[wDevID
].unixdev
);
781 WInDev
[wDevID
].unixdev
= 0;
782 WInDev
[wDevID
].bufsize
= 0;
783 if (WAVE_NotifyClient(wDevID
, WIM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
784 WARN(wave
,"can't notify client !\n");
785 return MMSYSERR_INVALPARAM
;
787 return MMSYSERR_NOERROR
;
790 /**************************************************************************
791 * widAddBuffer [internal]
793 static DWORD
widAddBuffer(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
798 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
799 if (WInDev
[wDevID
].unixdev
== 0) {
800 WARN(wave
,"can't do it !\n");
801 return MMSYSERR_NOTENABLED
;
803 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) {
804 TRACE(wave
, "never been prepared !\n");
805 return WAVERR_UNPREPARED
;
807 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) {
808 TRACE(wave
, "header already in use !\n");
809 return WAVERR_STILLPLAYING
;
811 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
812 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
813 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
814 lpWaveHdr
->dwBytesRecorded
= 0;
815 if (WInDev
[wDevID
].lpQueueHdr
== NULL
) {
816 WInDev
[wDevID
].lpQueueHdr
= lpWaveHdr
;
818 lpWIHdr
= WInDev
[wDevID
].lpQueueHdr
;
819 while (lpWIHdr
->lpNext
!= NULL
) {
820 lpWIHdr
= lpWIHdr
->lpNext
;
823 lpWIHdr
->lpNext
= lpWaveHdr
;
824 lpWaveHdr
->lpNext
= NULL
;
827 TRACE(wave
, "buffer added ! (now %u in queue)\n", count
);
828 return MMSYSERR_NOERROR
;
831 /**************************************************************************
832 * widPrepare [internal]
834 static DWORD
widPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
836 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
837 if (WInDev
[wDevID
].unixdev
== 0) {
838 WARN(wave
,"can't prepare !\n");
839 return MMSYSERR_NOTENABLED
;
841 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
842 return WAVERR_STILLPLAYING
;
843 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
844 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
845 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
846 lpWaveHdr
->dwBytesRecorded
= 0;
847 TRACE(wave
,"header prepared !\n");
848 return MMSYSERR_NOERROR
;
851 /**************************************************************************
852 * widUnprepare [internal]
854 static DWORD
widUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
856 TRACE(wave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
857 if (WInDev
[wDevID
].unixdev
== 0) {
858 WARN(wave
,"can't unprepare !\n");
859 return MMSYSERR_NOTENABLED
;
861 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
862 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
863 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
865 TRACE(wave
, "all headers unprepared !\n");
866 return MMSYSERR_NOERROR
;
869 /**************************************************************************
870 * widStart [internal]
872 static DWORD
widStart(WORD wDevID
)
877 LPWAVEHDR
*lpWaveHdr
;
879 TRACE(wave
,"(%u);\n", wDevID
);
880 if (WInDev
[wDevID
].unixdev
== 0) {
881 WARN(wave
, "can't start recording !\n");
882 return MMSYSERR_NOTENABLED
;
885 lpWaveHdr
= &(WInDev
[wDevID
].lpQueueHdr
);
886 TRACE(wave
,"lpWaveHdr = %08lx\n",(DWORD
)lpWaveHdr
);
887 if (!*lpWaveHdr
|| !(*lpWaveHdr
)->lpData
) {
888 TRACE(wave
,"never been prepared !\n");
889 return WAVERR_UNPREPARED
;
892 while(*lpWaveHdr
!= NULL
) {
893 lpWIHdr
= *lpWaveHdr
;
894 TRACE(wave
, "recording buf#%u=%p size=%lu \n",
895 count
, lpWIHdr
->lpData
, lpWIHdr
->dwBufferLength
);
897 bytesRead
= read (WInDev
[wDevID
].unixdev
,
899 lpWIHdr
->dwBufferLength
);
901 perror("read from audio device");
902 TRACE(wave
,"bytesread=%d (%ld)\n", bytesRead
, lpWIHdr
->dwBufferLength
);
903 lpWIHdr
->dwBytesRecorded
= bytesRead
;
904 WInDev
[wDevID
].dwTotalRecorded
+= lpWIHdr
->dwBytesRecorded
;
905 lpWIHdr
->dwFlags
&= ~WHDR_INQUEUE
;
906 lpWIHdr
->dwFlags
|= WHDR_DONE
;
908 /* FIXME: should pass segmented pointer here, do we need that?*/
909 if (WAVE_NotifyClient(wDevID
, WIM_DATA
, (DWORD
)lpWaveHdr
, lpWIHdr
->dwBytesRecorded
) != MMSYSERR_NOERROR
) {
910 WARN(wave
, "can't notify client !\n");
911 return MMSYSERR_INVALPARAM
;
913 /* removes the current block from the queue */
914 *lpWaveHdr
= lpWIHdr
->lpNext
;
917 TRACE(wave
,"end of recording !\n");
919 return MMSYSERR_NOERROR
;
922 /**************************************************************************
925 static DWORD
widStop(WORD wDevID
)
927 TRACE(wave
,"(%u);\n", wDevID
);
928 if (WInDev
[wDevID
].unixdev
== 0) {
929 WARN(wave
,"can't stop !\n");
930 return MMSYSERR_NOTENABLED
;
932 return MMSYSERR_NOERROR
;
935 /**************************************************************************
936 * widReset [internal]
938 static DWORD
widReset(WORD wDevID
)
940 TRACE(wave
,"(%u);\n", wDevID
);
941 if (WInDev
[wDevID
].unixdev
== 0) {
942 WARN(wave
,"can't reset !\n");
943 return MMSYSERR_NOTENABLED
;
945 return MMSYSERR_NOERROR
;
948 /**************************************************************************
949 * widGetPosition [internal]
951 static DWORD
widGetPosition(WORD wDevID
, LPMMTIME16 lpTime
, DWORD uSize
)
955 TRACE(wave
, "(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
956 if (WInDev
[wDevID
].unixdev
== 0) {
957 WARN(wave
,"can't get pos !\n");
958 return MMSYSERR_NOTENABLED
;
960 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
961 TRACE(wave
,"wType=%04X !\n", lpTime
->wType
);
962 TRACE(wave
,"wBitsPerSample=%u\n", WInDev
[wDevID
].Format
.wBitsPerSample
);
963 TRACE(wave
,"nSamplesPerSec=%lu\n", WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
964 TRACE(wave
,"nChannels=%u\n", WInDev
[wDevID
].Format
.wf
.nChannels
);
965 TRACE(wave
,"nAvgBytesPerSec=%lu\n", WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
967 switch(lpTime
->wType
) {
969 lpTime
->u
.cb
= WInDev
[wDevID
].dwTotalRecorded
;
970 TRACE(wave
,"TIME_BYTES=%lu\n", lpTime
->u
.cb
);
973 lpTime
->u
.sample
= WInDev
[wDevID
].dwTotalRecorded
* 8 /
974 WInDev
[wDevID
].Format
.wBitsPerSample
;
975 TRACE(wave
, "TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
978 time
= WInDev
[wDevID
].dwTotalRecorded
/
979 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
980 lpTime
->u
.smpte
.hour
= time
/ 108000;
981 time
-= lpTime
->u
.smpte
.hour
* 108000;
982 lpTime
->u
.smpte
.min
= time
/ 1800;
983 time
-= lpTime
->u
.smpte
.min
* 1800;
984 lpTime
->u
.smpte
.sec
= time
/ 30;
985 time
-= lpTime
->u
.smpte
.sec
* 30;
986 lpTime
->u
.smpte
.frame
= time
;
987 lpTime
->u
.smpte
.fps
= 30;
988 TRACE(wave
,"TIME_SMPTE=%02u:%02u:%02u:%02u\n",
989 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
990 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
993 lpTime
->u
.ms
= WInDev
[wDevID
].dwTotalRecorded
/
994 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
995 TRACE(wave
, "TIME_MS=%lu\n", lpTime
->u
.ms
);
998 FIXME(wave
, "format not supported ! use TIME_MS !\n");
999 lpTime
->wType
= TIME_MS
;
1001 return MMSYSERR_NOERROR
;
1004 /**************************************************************************
1005 * widMessage [sample driver]
1007 DWORD WINAPI
widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1008 DWORD dwParam1
, DWORD dwParam2
)
1011 TRACE(wave
,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1012 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1015 return widOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1017 return widClose(wDevID
);
1018 case WIDM_ADDBUFFER
:
1019 return widAddBuffer(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1021 return widPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1022 case WIDM_UNPREPARE
:
1023 return widUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1024 case WIDM_GETDEVCAPS
:
1025 return widGetDevCaps(wDevID
, (LPWAVEINCAPS16
)dwParam1
,dwParam2
);
1026 case WIDM_GETNUMDEVS
:
1027 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1028 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
1039 return widGetPosition(wDevID
, (LPMMTIME16
)dwParam1
, dwParam2
);
1041 return widReset(wDevID
);
1043 return widStart(wDevID
);
1045 return widStop(wDevID
);
1047 return widStop(wDevID
);
1049 WARN(wave
,"unknown message !\n");
1051 return MMSYSERR_NOTSUPPORTED
;
1055 /**************************************************************************
1056 * WAVE_DriverProc16 [sample driver]
1058 LONG
WAVE_DriverProc16(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
1059 DWORD dwParam1
, DWORD dwParam2
)
1061 TRACE(wave
,"(%08lX, %04X, %04X, %08lX, %08lX)\n", dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1064 case DRV_LOAD
: return 1;
1065 case DRV_FREE
: return 1;
1066 case DRV_OPEN
: return 1;
1067 case DRV_CLOSE
: return 1;
1068 case DRV_ENABLE
: return 1;
1069 case DRV_DISABLE
: return 1;
1070 case DRV_QUERYCONFIGURE
: return 1;
1071 case DRV_CONFIGURE
: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK
); return 1;
1072 case DRV_INSTALL
: return DRVCNF_RESTART
;
1073 case DRV_REMOVE
: return DRVCNF_RESTART
;
1075 FIXME(wave
, "is probably wrong msg=0x%04x\n", wMsg
);
1076 return DefDriverProc16(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1078 return MMSYSERR_NOTENABLED
;
1081 /**************************************************************************
1082 * WAVE_DriverProc32 [sample driver]
1084 LONG
WAVE_DriverProc32(DWORD dwDevID
, HDRVR16 hDriv
, DWORD wMsg
,
1085 DWORD dwParam1
, DWORD dwParam2
)
1087 TRACE(wave
,"(%08lX, %04X, %08lX, %08lX, %08lX)\n", dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1089 case DRV_LOAD
: return 1;
1090 case DRV_FREE
: return 1;
1091 case DRV_OPEN
: return 1;
1092 case DRV_CLOSE
: return 1;
1093 case DRV_ENABLE
: return 1;
1094 case DRV_DISABLE
: return 1;
1095 case DRV_QUERYCONFIGURE
: return 1;
1096 case DRV_CONFIGURE
: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK
); return 1;
1097 case DRV_INSTALL
: return DRVCNF_RESTART
;
1098 case DRV_REMOVE
: return DRVCNF_RESTART
;
1100 FIXME(wave
, "is probably wrong msg=0x%04lx\n", wMsg
);
1101 return DefDriverProc32(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1103 return MMSYSERR_NOTENABLED
;
1106 #else /* !HAVE_OSS */
1108 /**************************************************************************
1109 * wodMessage [sample driver]
1111 DWORD WINAPI
wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1112 DWORD dwParam1
, DWORD dwParam2
)
1114 FIXME(wave
,"(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1115 return MMSYSERR_NOTENABLED
;
1118 /**************************************************************************
1119 * widMessage [sample driver]
1121 DWORD WINAPI
widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1122 DWORD dwParam1
, DWORD dwParam2
)
1124 FIXME(wave
,"(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1125 return MMSYSERR_NOTENABLED
;
1128 /**************************************************************************
1129 * WAVE_DriverProc16 [sample driver]
1131 LONG
WAVE_DriverProc16(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
1132 DWORD dwParam1
, DWORD dwParam2
)
1134 return MMSYSERR_NOTENABLED
;
1137 /**************************************************************************
1138 * WAVE_DriverProc32 [sample driver]
1140 LONG
WAVE_DriverProc32(DWORD dwDevID
, HDRVR16 hDriv
, DWORD wMsg
,
1141 DWORD dwParam1
, DWORD dwParam2
)
1143 return MMSYSERR_NOTENABLED
;
1145 #endif /* HAVE_OSS */